-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path213-vue-basic-props.ts
157 lines (144 loc) · 4.68 KB
/
213-vue-basic-props.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* 213 - Vue Basic Props
*
* **This challenge continues from [6 - Simple Vue](//tsch.js.org/6), you should finish that one first, and modify your code based on it to start this challenge**.
*
* In addition to the Simple Vue, we are now having a new `props` field in the options.
* This is a simplified version of Vue's `props` option. Here are some of the rules.
*
* `props` is an object containing each field as the key of the real props injected into `this`. The injected props will be accessible in all the context including `data`, `computed`, and `methods`.
*
* A prop will be defined either by a constructor or an object with a `type` field containing constructor(s).
*
* For example
*
* ```js
* props: {
* foo: Boolean
* }
* // or
* props: {
* foo: { type: Boolean }
* }
* ```
*
* should be inferred to `type Props = { foo: boolean }`.
*
* When passing multiple constructors, the type should be inferred to a union.
*
* ```ts
* props: {
* foo: { type: [Boolean, Number, String] }
* }
* // -->
* type Props = { foo: boolean | number | string }
* ```
*
* When an empty object is passed, the key should be inferred to `any`.
*
* For more specified cases, check out the Test Cases section.
*
* > `required`, `default`, and array props in Vue are not considered in this challenge.
*
*
* <!--info-footer-start--><br><a href="../../README.md" target="_blank"><img src="https://img.shields.io/badge/-Back-grey" alt="Back"/></a> <a href="https://tsch.js.org/213/answer" target="_blank"><img src="https://img.shields.io/badge/-Share%20your%20Solutions-teal" alt="Share your Solutions"/></a> <a href="https://tsch.js.org/213/solutions" target="_blank"><img src="https://img.shields.io/badge/-Check%20out%20Solutions-de5a77?logo=awesome-lists&logoColor=white" alt="Check out Solutions"/></a> <hr><h3>Related Challenges</h3><a href="https://github.com/type-challenges/type-challenges/blob/main/questions/00006-hard-simple-vue/README.md" target="_blank"><img src="https://img.shields.io/badge/-6%E3%83%BBSimple%20Vue-de3d37" alt="6・Simple Vue"/></a> <!--info-footer-end-->
*/
/* _____________ Your Code Here _____________ */
type MapComputedProps<C> = {
[K in keyof C]: C[K] extends (...arg: unknown[]) => infer R ? R : never
}
type GetPropType<T> = T extends unknown
? T extends StringConstructor
? string
: T extends BooleanConstructor
? boolean
: T extends NumberConstructor
? number
: T extends RegExpConstructor
? RegExp
: T extends Array<unknown>
? GetPropType<T[number]>
: T extends (new (...args: unknown[]) => infer R)
? R
: T
: never;
type MapProps<Props> = {
[K in keyof Props]: Props[K] extends { type: unknown }
? GetPropType<Props[K]['type']>
: {} extends Props[K]
? any
: GetPropType<Props[K]>
}
type Options<Props, Data, Computed, Methods> =
(MapProps<Props> & MapComputedProps<Computed> & Data & Methods) extends infer Context
? {
props: Props;
data: (this: MapProps<Props>) => Data;
computed: Computed & ThisType<Context>;
methods: Methods & ThisType<Context>;
}
: never;
declare function VueBasicProps<
Props,
Data,
Computed,
Methods,
>(options: Options<Props, Data, Computed, Methods>): any
/* _____________ Test Cases _____________ */
import type { Debug, Equal, Expect, IsAny } from '@type-challenges/utils'
class ClassA {}
VueBasicProps({
props: {
propA: {},
propB: { type: String },
propC: { type: Boolean },
propD: { type: ClassA },
propE: { type: [String, Number] },
propF: RegExp,
},
data(this) {
type PropsType = Debug<typeof this>
type A = PropsType['propD']
type cases = [
Expect<IsAny<PropsType['propA']>>,
Expect<Equal<PropsType['propB'], string>>,
Expect<Equal<PropsType['propC'], boolean>>,
Expect<Equal<PropsType['propD'], ClassA>>,
Expect<Equal<PropsType['propE'], string | number>>,
Expect<Equal<PropsType['propF'], RegExp>>,
]
// @ts-expect-error
this.firstname
// @ts-expect-error
this.getRandom()
// @ts-expect-error
this.data()
return {
firstname: 'Type',
lastname: 'Challenges',
amount: 10,
}
},
computed: {
fullname() {
return `${this.firstname} ${this.lastname}`
},
},
methods: {
getRandom() {
return Math.random()
},
hi() {
alert(this.fullname.toLowerCase())
alert(this.getRandom())
},
test() {
const fullname = this.fullname
const propE = this.propE
type cases = [
Expect<Equal<typeof fullname, string>>,
Expect<Equal<typeof propE, string | number>>,
]
},
},
})