Issue
I have a situation where I want the type of the value field to be constrained by the type of the Type field. Please see demo1
// demo1
type PropType<T = any> = { new (...arg: any[]): T } | { (): T };
type InferPropType<T> = T extends PropType<infer R> ? R : never;
type FullProperties<Type> = {
type: Type;
value?: InferPropType<Type>;
};
const defineComponent = function <
TProperties extends Record<string, FullProperties<PropType<string>>>,
>(options: { properties: TProperties }) {};
const test = defineComponent({
properties: {
str:{
type:String,
value:123, // an error here. happy
},
gender0: {
type: String as PropType<'male' | 'female'>,
value: 'male', // or 'female' expect ok
},
gender1: {
type: String as PropType<'male' | 'female'>,
value: 'string', // expect error ` Type 'string' cannot be assigned to type 'male' | 'female' `
},
},
});
I want to extract the generic to constrain the value field I tried the following
// demo2
const defineComponent1 = function <
TProperties extends Record<string, FullProperties<Type>>,
Type,
>(options: { properties: TProperties }) {};
const test1 = defineComponent1({
properties: {
gender0: {
type: String as PropType<'male' | 'female'>,
value: 'male',// Cannot assign type 'number' to type 'never'
},
},
});
How do you do that? Is it possible?
@captain-yossarian There are two more highlights here , Can be turned into a? please see playground
Solution
You need to do some tricky validation here. Consider this example:
type PropType<T extends string> = { new(...arg: any[]): T } | { (): T };
type InferPropType<T> = T extends PropType<infer R> ? R : never;
type Validation<T extends Record<string, { type: unknown, value: unknown }>> = {
[Prop in keyof T]: T[Prop] extends { type: infer Type }
? { type: Type, value: InferPropType<Type> }
: never
}
const defineComponent = <
Value extends string,
Entity extends { type: PropType<Value>, value: Value },
Properties extends Record<string, Entity>,
>(options: { properties: Properties & Validation<Properties> }) => { };
const test = defineComponent({
properties: {
str: {
type: String,
value: 123, // an error here. happy
},
gender0: {
type: String as PropType<'male' | 'female'>,
value: 'male', // or 'female' expect ok
},
gender1: {
type: String as PropType<'male' | 'female'>,
value: 'string', // TS will highlight it an an error once you fix first error [value: 123]
},
},
});
Validation
- utility type iterates through infered Properties
property and assures that each value which has type
property implements this interface { type: Type, value: InferPropType<Type> }
.
As you might have noticed value: 123
is an error but value: 'string'
is not. No worries. Try to fix first error and TS will highlight value:"string"
as an error.
If you are interested in function arguments inference and type validation you can check my articles here and here
Answered By - captain-yossarian
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.