type GetPropsType<T> = T extends { new(...args: never): infer Inst & { valueOf: () => infer R } } ? R extends object ? Inst : R : any
type GetProps<P> = {
[K in keyof P]: P[K] extends { 'type': infer Ctor | (infer Ctor)[] } ? GetPropsType<Ctor> : GetPropsType<P[K]>
}
type GetComputed<C> = {
[P in keyof C]: C[P] extends (...args: never) => unknown ? ReturnType<C[P]> : never
}
declare function VueBasicProps<P, D, C, M>(
options: {
props: P,
data: (this: GetProps<P>) => D,
computed: C,
methods: M,
} & ThisType<GetProps<P> & D & GetComputed<C> & M>
): any
Solution by 2083335157 #35033
declare function VueBasicProps<P, D, C, M>(
options: VueOptions<P, D, C, M>
): unknown;
type GetComputed<T> = {
[P in keyof T]: T[P] extends () => infer Res ? Res : T[P];
};
type MaybeReturnType<T> = T extends (...args: any) => infer R
? R
: T extends new (...args: any) => infer R1
? R1
: T;
type GetProps<T> = {
[P in keyof T]: T[P] extends {
type: infer Prop;
}
? Prop extends any[]
? MaybeReturnType<Prop[number]>
: MaybeReturnType<Prop>
: Equal<T[P], {}> extends true ? any : MaybeReturnType<T[P]>;
};
type VueOptions<P, D, C, M> = {
props: P;
data: (this: GetProps<P>) => D;
computed: C & ThisType<D & GetComputed<C>>;
methods: M & ThisType<D & GetComputed<C> & M & GetProps<P>>;
};
Solution by Vampirelee #32612
type GetComputed<Obj> = {
[key in keyof Obj]: Obj[key] extends () => infer R ? R : Obj[key]
}
type GetType<Ctor> = Ctor extends (...args: any[]) => infer R // for string and number to return type
? R
: Ctor extends Array<() => unknown> // is Array
? ReturnType<Ctor[number]>
: Ctor extends new (...args: any[]) => infer R // is Constructor
? R
: Ctor
type GetProps<Obj> = {
[key in keyof Obj]: Obj[key] extends { type: infer Ctor }
? GetType<Ctor>
: {} extends Obj[key]
? any
: GetType<Obj[key]>
}
declare function VueBasicProps<Props, Data, Computed, Methods>(options: {
props: Props
data: (this: GetProps<Props>) => Data,
computed: Computed & ThisType<Data>,
methods: Methods & ThisType<Data & GetComputed<Computed> & Methods & GetProps<Props>>
}): any
Solution by HoikanChan #32584
type Constructor<T> = T extends (infer U)[]
? Constructor<U>
: T extends StringConstructor
? string
: T extends NumberConstructor
? number
: T extends BooleanConstructor
? boolean
: T extends new (...args: any[]) => infer C
? C
: any;
type Props<T> = {
[K in keyof T]: T[K] extends { type: infer U }
? Constructor<U>
: Constructor<T[K]>;
};
declare function VueBasicProps<T, D, C, M>(options: {
props: T;
data: (this: Props<T>) => D;
computed: C & ThisType<D>;
methods: M &
ThisType<
D &
M & {
[K in keyof C]: C[K] extends (...args: any[]) => any
? ReturnType<C[K]>
: never;
} & Props<T>
>;
}): any;
Solution by vangie #32316
type AnyClass = new (...args: any[]) => unknown
type TransformComputed<T> = {
readonly [K in keyof T]: T[K] extends (...args: any[]) => any ? ReturnType<T[K]> : never
}
type TransformProps<T> = {
[K in keyof T]: T[K] extends { type: infer R extends AnyClass | AnyClass[] }
? MultipleToPrimitive<R>
: T[K] extends AnyClass
? InstanceType<T[K]>
: any
}
type ToPrimitive<T extends AnyClass, R = InstanceType<T>> = R extends {
valueOf: () => infer S
}
? S
: never
type MultipleToPrimitive<T extends AnyClass | AnyClass[]> = T extends AnyClass
? ToPrimitive<T>
: T extends (infer R extends AnyClass)[]
? ToPrimitive<R>
: never
type VueProps = Record<string, any>
type VueMethods = Record<string, (...args: any[]) => unknown>
type VueComputed = Record<string, Function>
type VueData = Record<string, unknown>
type VueBasicOptions<
Props extends VueProps,
Data extends VueData,
Computed extends VueComputed,
Methods extends VueMethods,
> = {
props: Props
data: (this: TransformProps<Props>) => Data
computed: Computed & ThisType<TransformProps<Props> & Data & TransformComputed<Computed> & Methods>
methods: Methods & ThisType<TransformProps<Props> & Data & TransformComputed<Computed> & Methods>
}
type VueBasicResult<
Props extends VueProps,
Data extends VueData,
Computed extends VueComputed,
Methods extends VueMethods,
> = TransformComputed<Props> & Data & Methods
declare function VueBasicProps<
Props extends VueProps,
Data extends VueData,
Computed extends VueComputed,
Methods extends VueMethods,
>(options: VueBasicOptions<Props, Data, Computed, Methods>): VueBasicResult<Props, Data, Computed, Methods>
/* _____________ Test Cases _____________ */
import type { Debug } from '@type-challenges/utils'
import type { Equal } from '@type-challenges/utils'
import type { Expect } from '@type-challenges/utils'
import type { 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 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
const prop = this.propB
type cases = [Expect<Equal<typeof fullname, string>>, Expect<Equal<typeof propE, string | number>>]
},
},
})
/* _____________ Further Steps _____________ */
/*
> Share your solutions: https://tsch.js.org/213/answer
> View solutions: https://tsch.js.org/213/solutions
> More Challenges: https://tsch.js.org
*/
type MultipleToPrimitiveOldVersion<T extends AnyClass | AnyClass[]> = T extends [
infer S extends AnyClass,
...infer Rest extends AnyClass[],
]
? ToPrimitive<S> | MultipleToPrimitive<Rest>
: T extends AnyClass
? ToPrimitive<T>
: never
Solution by gearonixx #31911
declare function defineStore<S,G,A>(store: Store<S,G,A>): A&S&RemapGetter<G>
type RemapGetter<T> = {
[P in keyof T]: T[P] extends ()=> infer R ? R :never
}
type Store<State,G,A> ={
state:()=>State
getters:G&ThisType<Readonly<State>&RemapGetter<G>>
actions:ThisType<State&A>&A,
id:string
}
Solution by manyuemeiquqi #29465
Ok. You can try this one. This one picks up from yesterday's "Simple Vue" challenge and introduces the concept of "props". If you have (and understand) yesterday's challenge, then this one should be pretty approachable.
// ============= Test Cases =============
import type { Equal, Expect, IsAny } from './test-utils'
class ClassA {}
VueBasicProps({
props: {
propA: {},
propB: { type: String },
propC: { type: Boolean },
propD: { type: ClassA },
propE: { type: [String, Number] },
propF: RegExp,
},
data(this) {
type A1 = IsAny<typeof this['propA']>;
type B1 = true;
type C1 = Expect<Equal<A1, B1>>;
type A2 = typeof this['propB'];
type B2 = string;
type C2 = Expect<Equal<A2, B2>>;
type A3 = typeof this['propC'];
type B3 = boolean;
type C3 = Expect<Equal<A3, B3>>;
type A4 = typeof this['propD'];
type B4 = ClassA;
type C4 = Expect<Equal<A4, B4>>;
type A5 = typeof this['propE'];
type B5 = string | number;
type C5 = Expect<Equal<A5, B5>>;
type A6 = typeof this['propF'];
type B6 = RegExp;
type C6 = Expect<Equal<A6, B6>>;
// @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() {
type A7 = typeof this.fullname;
type B7 = string;
type C7 = Expect<Equal<A7, B7>>;
type A8 = typeof this.propE;
type B8 = string | number;
type C8 = Expect<Equal<A8, B8>>;
},
},
});
// ============= Your Code Here =============
type ResultType<T> =
T extends (...args: any[]) => infer R
? R
: T extends new (...args: unknown[]) => infer S
? S
: any;
type PropsTypes<T> = {
[P in keyof T]:
T[P] extends { type: infer Result }
? Result extends readonly unknown[]
? ResultType<Result[number]>
: ResultType<Result>
: ResultType<T[P]>
};
declare function VueBasicProps<
Props,
Data,
Computed extends
Record<PropertyKey, (...args: unknown[]) => unknown>,
Methods,
>(
options: {
props: Props,
data(this: PropsTypes<Props>): Data,
computed: Computed & ThisType<Data>,
methods:
& Methods
& ThisType<
& PropsTypes<Props>
& Methods
& {
[P in keyof Computed]:
ReturnType<Computed[P]>
}
>,
}
): unknown;
For more video solutions to other challenges: see the umbrella list! https://github.com/type-challenges/type-challenges/issues/21338
Solution by dimitropoulos #26114
type ReturnType<F> = F extends (...args: infer A) => infer R ? R : F;
type GetValues<C extends Record<PropertyKey, any>> = { [K in keyof C]: ReturnType<C[K]> };
type Computed<C extends Record<PropertyKey, any>, T> =
{ [K in keyof C]: (this: T, ...args: unknown []) => ReturnType<C[K]> };
type Methods<M extends Record<PropertyKey, any>, T> =
{ [K in keyof M]: (this:T, ...args: unknown []) => ReturnType<M[K]> };
type Data<D> = (this: Data<D>, ...args: unknown[]) => D ;
declare function SimpleVue<
D extends Record<PropertyKey, any>,
C extends Record<PropertyKey, () => any>,
M extends Record<PropertyKey, () => any>
>(options: {
data: Data<D>,
computed: Computed<C, D>,
methods: Methods<M, D & GetValues<C> & Methods<M, D & GetValues<C>>>
}): Data<D> & Computed<C, D> & Methods<M, D & GetValues<C> & Methods<M, D & GetValues<C>>>;
Solution by JhonLandy #25874
type BaseType<B> = B extends new (...args: any) => infer R
? B extends { (value?: any): infer T }
? T
: R
: B;
type PropsParse<P> = {
[Key in keyof P]: BaseType<
P[Key] extends Record<PropertyKey, never>
? any
: P[Key] extends { type: any }
? P[Key]["type"] extends any[]
? P[Key]["type"][number]
: P[Key]["type"]
: P[Key]
>;
};
declare function VueBasicProps<
D,
C extends Record<PropertyKey, (...args: any) => any>,
M,
P
>(options: {
props: P;
data: (this: void & PropsParse<P>) => D;
computed: C & ThisType<D & PropsParse<P>>;
methods: M &
ThisType<D & M & { [K in keyof C]: ReturnType<C[K]> } & PropsParse<P>>;
}): any;
Solution by ickynavigator #25334
// your answers
type ToBaseType<T> = T extends (infer K)[]
? ToBaseType<K>
: T extends new (...args: any) => infer R
? T extends { (value?: any): infer B }
? B
: R
: T
type GetProps<T extends object> = {
[P in keyof T]: T[P] extends { [x: string]: never }
? any
: ToBaseType<T[P] extends { type: infer K } ? K : T[P]>
}
declare function VueBasicProps<
T extends { [x: PropertyKey]: any },
U extends { [x: string]: () => unknown },
V extends { [x: string]: () => unknown },
W extends { [x: string]: any }
>(options: {
props: W
data: (this: GetProps<W>) => T
computed: U & ThisType<T>
methods: V &
ThisType<
V &
T & {
[P in keyof U]: U[P] extends () => infer R ? R : never
} & GetProps<W>
>
}): any
Solution by studymachiney #25128
type ToBaseType<T> = T extends (infer TT)[] ? // [Type1, Type2, ...]
ToBaseType<TT> : // ToBaseType<Type1 | Type2 | ...>
(T extends new (...args: any) => infer I ? // ClassConstructor => insType
(T extends { (value?: any): infer B } ? // TypeConstructor => baseType
B : // baseType
I) : // insType
T);
/**Props ThisType */
type __PropsThisType<W> = { [P in keyof W]: W[P] extends { [x: string]: never } ? any : //{}
ToBaseType<W[P] extends { type: infer TT } ? TT : W[P]> };
declare function VueBasicProps<
T extends { [x: PropertyKey]: any },
U extends { [x: string]: () => unknown },
V extends { [x: string]: () => unknown },
W extends { [x: string]: any }>(options: {
data: (this: __PropsThisType<W>) => T,
computed: U & ThisType<T>,
methods: V & ThisType<V & T & { [P in keyof U]: U[P] extends () => infer R ? R : never } & __PropsThisType<W>>,
props: W
}): any
Solution by E-uler #24701
// your answers
type PropConstructor<T> =
|{new (...args:any[]): T&object}
| {():T}
type PropType<T> = PropConstructor<T> | PropConstructor<T>[]
type Props<T> = PropType<T> | {type?:PropType<T>}
type inferPropType<T> = T extends Props<infer P>
? unknown extends P
? any
: P
:any
type inferPropsType<T> = {
[K in keyof T]:inferPropType<T[K]>
}
type inferComputed<T extends Record<string,any>> = {
[K in keyof T]:ReturnType<T[K]>
}
declare function VueBasicProps<
P,
D,
C extends Record<string,any>,
M,
Props=inferPropsType<P>
>(options: {
props:P,
data:(this:Props)=>D
computed:C&ThisType<Props&D&inferComputed<C>&M>
methods:M&ThisType<Props&D&inferComputed<C>&M>
}): any
Solution by walker-hzx #24539
type Computed<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => infer R ? R : T[K]
}
type GetPropType<T> =
T extends unknown[]
? GetPropType<T[number]>
: T extends (...args: any) => any
? ReturnType<T>
: T extends new (...args: any) => any
? InstanceType<T>
: T
type Props<T> = {
[K in keyof T]: T[K] extends Record<string, never>
? any
: T[K] extends { type: infer R }
? GetPropType<R>
: GetPropType<T[K]>
}
interface Options<D, C, M, P> {
props: P
data?: (this: Props<P>) => D
computed?: C & ThisType<D & Computed<C> & M & Props<P>>
methods?: M & ThisType<D & Computed<C> & M & Props<P>>
}
declare function VueBasicProps<D, C, M, P> (options: Options<D, C, M, P>): any
Solution by drylint #23167
// your answers
type ToBase<T> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BooleanConstructor ? boolean : T extends RegExpConstructor ? RegExp : T extends new (...args: any[]) => infer R ? R : T
type RecordFunction = Record<string, Function>;
type PropType = String | Array<any> | Record<string,any> | Number;
type PropsType = Record<string, {type: PropType | PropType[]} | PropType | PropType[]>
type ArrayToBase<T> = T extends any[] ? ToBase<T[number]> : ToBase<T>
type TransProps<T extends PropsType> = {
[key in keyof T]: {} extends T[key] ? any : 'type' extends keyof T[key] ? ArrayToBase<T[key]['type']> : ArrayToBase<T[key]>
}
type TransComputed<T extends RecordFunction> = {
[key in keyof T]: T[key] extends (...args: any[]) => infer R ? R : T
}
type Vue<
D extends Record<string, any>,
C extends RecordFunction,
M extends RecordFunction,
P extends PropsType,
_TransProps = TransProps<P>,
_TransComputed = TransComputed<C>
> = {
data: (this: _TransProps) => D,
computed: C & ThisType<D & M & _TransComputed & _TransProps>,
methods: M & ThisType<D & M & _TransComputed & _TransProps>,
props: P
}
declare function VueBasicProps<
D extends Record<string, any>,
C extends RecordFunction,
M extends RecordFunction,
P extends PropsType,
>(options: Vue<D, C, M, P>): any
Solution by 437204933 #22292
// 乱七八糟,,, ParseProps 整了好久才把红线去掉,弄完感觉又学到了没用的姿势。。。
type ParseProps<P> = {
[K in keyof P]
: P[K] extends (_: any) => infer KK ? KK
: P[K] extends { [_: keyof any]: never } ? any
: P[K] extends { type: (() => infer KK) } ? KK
: P[K] extends { type: (new () => infer KK) } ? KK
: P[K] extends { type: (infer KK)[] }
? KK extends (_: any) => infer KKK ? KKK : '' : ''
}
type Computed<C> = { [K in keyof C]: C[K] extends (..._: any) => infer R ? R : C[K] }
type VueOption<P, D, C, M> = {
props?: P;
data?: (this: ParseProps<P>) => D
computed?: C & ThisType<D>;
methods
?: M & ThisType<
Computed<{ [K in keyof C]: C[K] extends (..._: any) => infer R ? R : C[K] }>
& D & M & ParseProps<P>
>
}
declare function VueBasicProps<P, D, C, M>(options: VueOption<P, D, C, M>): VueOption<P, D, C, M>
Solution by goddnsgit #21877
type RecordFunction = Record<string, Function>;
type TransitionComputed<T extends RecordFunction> = {
[P in keyof T]: T[P] extends () => infer A ? A : never;
};
type PropType = String | Array<any> | Record<string,any> | Number;
type PropsType = Record<string,{
type?:PropType | Array<PropType>
} | PropType>
type mappingProps<T> =
T extends BooleanConstructor?
boolean :
T extends NumberConstructor ?
number :
T extends StringConstructor ?
string :
T extends RegExpConstructor ?
RegExp :
T extends new (...args: any) => infer R ? R :T;
type TransitionProps<T extends PropsType> = {
[P in keyof T]:{} extends T[P] ? any : T[P] extends {
type:infer R
} ? R extends Array<any> ? mappingProps<R[number]>: mappingProps<R> : mappingProps<T[P]>
}
type Vue<
Data extends Record<string, any>,
Computed extends RecordFunction,
Methods extends RecordFunction,
Props extends PropsType,
_TransitionComputed = TransitionComputed<Computed>,
_TransitionProps =TransitionProps<Props>,
> = {
data?(this:_TransitionProps): Data;
props:Props;
computed?: Computed & ThisType<Methods & _TransitionComputed & Data & _TransitionProps>;
methods?: Methods & ThisType<Methods & _TransitionComputed & Data & _TransitionProps>;
};
declare function VueBasicProps<
Data extends Record<string, any>,
Computed extends RecordFunction,
Methods extends RecordFunction,
Props extends PropsType
>(options: Vue<Data, Computed, Methods,Props>): any;
Solution by so11y #21111
type TInstance<T> =
T extends { (...args: any): infer R } ? R :
T extends abstract new (...args: any) => infer R ? R :
T extends Record<string | number | symbol, never> ? any :
T extends (infer S)[] ? TInstance<S> :
T extends { type: infer S } ? TInstance<S> : never;
type TComputed<T> = {[K in keyof T]: T[K] extends (...args: unknown[]) => infer R ? R : never};
type TProps<P> = {[K in keyof P]: TInstance<P[K]>};
declare function VueBasicProps<D, C, M, P>(options: {
props: P,
data: (this: TProps<P>) => D,
computed: C & ThisType<D & TComputed<C> & TProps<P>>,
methods: M & ThisType<D & TComputed<C> & M & TProps<P>>,
}): any
Solution by kenleung5e28 #20575
type PropType2Type<T> =
T extends StringConstructor
? string
: T extends NumberConstructor
? number
: T extends BooleanConstructor
? boolean
: T extends (infer TS)[]
? PropType2Type<TS>
: T extends abstract new (...args: any) => any
? InstanceType<T>
: T
type VueProps<P> = {
[K in keyof P]:
P[K] extends Record<string,never>
? any
: P[K] extends { type: infer PT }
? PropType2Type<PT>
: PropType2Type<P[K]>
}
type VueComputed<C> = {
[P in keyof C]: C[P] extends () => unknown ? ReturnType<C[P]> : never
}
type VueThis<P, D, C, M> = ThisType<VueProps<P> & D & VueComputed<C> & M>
type VueOptions<P, D, C, M> = {
props: P;
data: (this: VueProps<P>) => D;
computed: C & VueThis<P, D, C, M>;
methods: M & VueThis<P, D, C, M>
}
declare function VueBasicProps<P, D, C, M>(options: VueOptions<P, D, C, M>): unknown
自言自语
学到的点
abstract new (...args: any) => any
可以表示 constructor 类型函数InstanceType
工具可以获取一个构造函数的返回物的类型
上述方案比较偏『正向推导』,即,顺着形态,描述的是判断过程,偏过程化
https://github.com/type-challenges/type-challenges/issues/215 的解决方案基于类型推断,模式匹配,更偏描述式,更易于理解维护(推荐)
直接描述数据结构,然后 infer 一下子提取到最终类型
Solution by zhaoyao91 #20446
declare function VueBasicProps<
// Base
Props, Data, Computed, Methods,
// Helper
_ThisProps = {
[P in keyof Props]: Props[P] extends ReturnType<
/**/<Help extends ((() => infer T) | (abstract new (...args: any) => infer T & object))>() =>
/* */{ type?: Help | Help[] } | Help | Help[]
> ? unknown extends T
? any
: T
: never
},
_ThisComputed = {
[P in keyof Computed]: Computed[P] extends (...args: any) => infer R
? R
: never
},
>(options: {
props?: Props,
data?: (this: _ThisProps) => Data,
computed?: Computed & ThisType<Data & _ThisComputed & _ThisProps>
methods?: Methods & ThisType<Data & Methods & _ThisComputed & _ThisProps>,
}): any
Solution by lvjiaxuan #19188
type InferComputed<C> = C extends Record<string, (...args: any[]) => any>
? { [S in keyof C]: ReturnType<C[S]> }
: never
type Prop<T> = PropType<T> | { type?: PropType<T> }
type PropType<T> = PropConstructor<T> | PropConstructor<T>[]
type PropConstructor<T> = | { new (...args: any[]): T & object } | { (): T }
type InferProps<P> = P extends Prop<infer T>
? unknown extends T
? any
: T
: any
type Props<T = any> = {
[S in keyof T]: InferProps<T[S]>
}
declare function VueBasicProps<P, D, C, M>(
options: {
props: P,
data(this: Props<P>): D,
computed: C,
methods: M
} & ThisType<D & M & InferComputed<C> & Props<P>>
): any
Solution by milletlovemouse #18575
type GetRes<T> = T extends (...args: any[]) => infer R ? R : T extends abstract new (...args: any[]) => infer R ? R : any
declare function VueBasicProps<Props, Data, Computed, Methods, _Computed = {
[key in keyof Computed]: GetRes<Computed[key]>
}, _Props = {
[key in keyof Props]: Props[key] extends { type: infer T } ? T extends any[] ? GetRes<T[number]> : GetRes<T> : GetRes<Props[key]>
}>(options: {
props: Props & ThisType<void>,
data: (this: _Props) => Data,
computed: Computed
methods: Methods
} & ThisType<_Props & Data & _Computed & Methods>): any
Solution by BulatDashiev #16894
// your answers
type GetRes<T> = T extends () => infer R ? R : T extends abstract new(...args: any) => any ? InstanceType<T> : never
type GetComputed<T> = {
[p in keyof T]: GetRes<T[p]>
}
type Props<T> = {
[p in keyof T]: T[p] extends { type: infer R } ? R extends any[] ? GetRes<R[number]>
: GetRes<R>
: keyof T[p] extends never ? any
: InstanceType<T[p]>
}
declare function VueBasicProps<P, D, C, M>(options: {
props: P
data(this: Props<P>): D & ThisType<P>
computed: C & ThisType<D & C>
methods: M & ThisType<D & GetComputed<C> & M & Props<P>>
}): any
Solution by Stan-BK #16432
// your answers
type Constructor = new (...args: any) => any
type PropsValue = Constructor | { type?: Constructor | Constructor[] }
type ConstructorMap<T> = T extends undefined
? any
: T extends StringConstructor
? string
: T extends NumberConstructor
? number
: T extends RegExpConstructor
? RegExp
: T extends BooleanConstructor
? boolean
: T extends Constructor[]
? ConstructorMap<T[number]>
: T extends { prototype: infer P }
? P
: any
type PropsContext<T> = {
[K in keyof T]: T[K] extends { type: infer R }
? ConstructorMap<R>
: ConstructorMap<T[K]>
}
type OptionsType<Props extends Record<string, PropsValue>, Data, Computed, Methods> = {
props?: Props,
data?: (this: PropsContext<Props>) => Data;
computed?: Computed & ThisType<Data & {
[P in keyof Computed]: Computed[P] extends (...args: any) => infer R
? R
: never
} & PropsContext<Props>>;
methods?: Methods & ThisType<PropsContext<Props> & Data & {
[P in keyof Computed]: Computed[P] extends (...args: any) => infer R
? R
: never
} & Methods>;
}
declare function VueBasicProps<Props extends Record<string, PropsValue>, Data, Computed, Methods>(options: OptionsType<Props, Data, Computed, Methods>): any
Solution by humandetail #16422
// your answers
type ToResultTypes<
T extends object> =
{[J in keyof T] : T[J] extends (...args:any[])=>infer R ? R : T[J]} ;
type ResultType<
T> =
T extends (...args:any[])=>infer R
? R
: T extends new (...args:any[])=>infer S
? S
: any ;
type PropsTypes<
P> =
{[J in keyof P]
: P[J] extends {type: infer R}
? R extends readonly any[]
? ResultType<R[number]>
: ResultType<R>
: ResultType<P[J]> } ;
type T<
P extends object,
C extends object,
M extends object,
S extends object >=
{
props:P,
data(this:PropsTypes<P>):S,
computed: C&ThisType<S>,
methods: M&ThisType<PropsTypes<P>&M&ToResultTypes<C>>,
} ;
declare function VueBasicProps<
P extends object,
S extends object,
C extends object,
M extends object
>(options: T<P,S,C,M>): unknown ;
Solution by justBadProgrammer #15818
// your answers
type getType<T> = T extends String | Number | Boolean ? T extends { valueOf(): infer R } ? R : T : T
type OptionsByProps<P> = {
[K in keyof P]:
P[K] extends new (...args: any[]) => infer R ? R :
P[K] extends { type: new (...args: any[]) => infer R } ? getType<R> :
P[K] extends { type: (new (...args: any[]) => infer R)[] } ? getType<R> :
P[K] extends {} ? any :
P[K]
}
type OptionsByComputed<C> = {
[K in keyof C]:
C[K] extends (...args: any[]) => infer R ? R :
never
}
type getOptions<D, P, C, M> = D & OptionsByProps<P> & M & OptionsByComputed<C>
type Options1<D, P, C, M> = {
props: P
data: (this: OptionsByProps<P>) => D & ThisType<getOptions<D, P, C, M>>
computed: C & ThisType<getOptions<D, P, C, M>>
methods: M & ThisType<getOptions<D, P, C, M>>
}
declare function VueBasicProps<D, P, C, M>(options: Options1<D, P, C, M>): any
Solution by fat-like-two #14878
// your answers
type getType<T> = T extends String | Number | Boolean ? T extends { valueOf(): infer R } ? R : T : T
type OptionsByProps<P> = {
[K in keyof P]:
P[K] extends new (...args: any[]) => infer R ? R :
P[K] extends { type: new (...args: any[]) => infer R } ? getType<R> :
P[K] extends { type: (new (...args: any[]) => infer R)[] } ? getType<R> :
P[K] extends {} ? any :
P[K]
}
type OptionsByComputed<C> = {
[K in keyof C]:
C[K] extends (...args: any[]) => infer R ? R :
never
}
type getOptions<D, P, C, M> = D & OptionsByProps<P> & M & OptionsByComputed<C>
type Options1<D, P, C, M> = {
props: P
data: (this: OptionsByProps<P>) => D & ThisType<getOptions<D, P, C, M>>
computed: C & ThisType<getOptions<D, P, C, M>>
methods: M & ThisType<getOptions<D, P, C, M>>
}
declare function VueBasicProps<D, P, C, M>(options: Options1<D, P, C, M>): any
Solution by fat-like-two #14877
// your answers
type getType<T> = T extends String | Number | Boolean ? T extends { valueOf(): infer R } ? R : T : T
type OptionsByProps<P> = {
[K in keyof P]:
P[K] extends new (...args: any[]) => infer R ? R :
P[K] extends { type: new (...args: any[]) => infer R } ? getType<R> :
P[K] extends { type: (new (...args: any[]) => infer R)[] } ? getType<R> :
P[K] extends {} ? any :
P[K]
}
type OptionsByComputed<C> = {
[K in keyof C]:
C[K] extends (...args: any[]) => infer R ? R :
never
}
type getOptions<D, P, C, M> = D & OptionsByProps<P> & M & OptionsByComputed<C>
type Options1<D, P, C, M> = {
props: P
data: (this: OptionsByProps<P>) => D & ThisType<getOptions<D, P, C, M>>
computed: C & ThisType<getOptions<D, P, C, M>>
methods: M & ThisType<getOptions<D, P, C, M>>
}
declare function VueBasicProps<D, P, C, M>(options: Options1<D, P, C, M>): any
Solution by fat-like-two #14876
type Constructor = new (...args: any) => any;
type ConstructorMap<T> =
T extends undefined
? any
: T extends StringConstructor
? string
: T extends BooleanConstructor
? boolean
: T extends NumberConstructor
? number
: T extends RegExpConstructor
? RegExp
: T extends Constructor[]
? ConstructorMap<T[number]>
: T extends {
prototype: infer C
}
? C
: any
declare function VueBasicProps<
Props extends Record<string, Constructor | { type?: Constructor | Constructor[] }>,
Data,
Computed,
Methods
>(options: {
props: Props & ThisType<null>,
data (this: {
[key in keyof Props]: Props[key] extends { type: infer P } ? ConstructorMap<P> : ConstructorMap<Props[key]>
}): Data,
computed: Computed,
methods: Methods,
} & ThisType<{
[key in keyof Props]: Props[key] extends { type: infer P } ? ConstructorMap<P> : ConstructorMap<Props[key]>
} & Data & {
[key in keyof Computed]: Computed[key] extends () => infer Result ? Result : never
} & Methods extends infer Result ? {
[key in keyof Result]: Result[key]
} : never>): any
Solution by cool-zero #14181
// The `computed` section needs to know about the inferred Props as it is an object
// where `this` is bound to those props.
type Computed<Props> = {
[key: string]: (this: Props) => any
}
// We need a helper which converts the function-typed values in the `computed` section to
// their actual types, which will be the return types of these functions.
// We could certainly improve this and disallow non-function valued items in the object.
type Compute<T extends object> = {
[P in keyof T]:
T[P] extends (...args: any[]) => infer Return
? Return
: never
}
// Methods get `this` bound to an interface which contains everything specified before -
// so the props, the 'computed' `computed` section and all the methods themselves!
type MethodsContext<Props, Computed extends object> =
Props
&
Compute<Computed>
&
Methods<Props, Computed>
// Methods is pretty simple - the complexity is in the interface that `this` implements
type Methods<Props, Computed extends object> = {
[key: string]: (this: MethodsContext<Props, Computed>, ...args: any[]) => any
}
type Options<Props, Computed extends object> = {
data: (this: never) => Props,
computed: Computed,
methods: Methods<Props, Computed>
}
declare function SimpleVue<
Props,
ComputedWithProps extends Computed<Props>
>(
options: Options<Props, ComputedWithProps>
): any
Solution by its-lee #13769
type PropsMap<T> = T extends (...args: any[]) => infer R1
? R1
: T extends new (...args: any[]) => infer R2
? R2
: never
type GetProps<P> = {
[key in keyof P]: P[key] extends { type: infer R }
? R extends (infer P)[]
? PropsMap<P>
: PropsMap<R>
: Equal<P[key], {}> extends true
? any
: PropsMap<P[key]>
}
type GetComputed<C> = {
[key in keyof C]: ReturnType<
C[key] extends (...args: any) => any ? C[key] : never
>
}
declare function VueBasicProps<P, D, C, M>(options: {
props: P
data: (this: GetProps<P>) => D
computed: C & ThisType<D>
methods: M & ThisType<M & D & GetComputed<C> & GetProps<P>>
}): any
Solution by yukinotech #12897