我确实有以下代码:
purrr
我正在尝试验证传递给type DomainFieldDefinition<T> = {
required?: boolean
}
type DomainDefinition<F, M> = {
fields?: { [K in keyof F]: DomainFieldDefinition<F[K]> },
methods?: { [K in keyof M]: M[K] & Function },
}
type User = {
id: string,
name?: string
}
export const User = createDomain<User>({
fields: {
id: { required: true },
name: {},
},
});
方法的字段的定义对象中的required
键的值是否与其所基于的类型的要求相匹配(此处为{ {1}});理想情况是在编译时。
我觉得条件类型可能有助于这样做,但是我找不到基于需求的方法。具体来说,我试图将createDomain
限制为:
User
,如果该字段不可为空,required
或未定义有任何提示吗?
答案 0 :(得分:1)
以定义为here 的类型为例,我们可以创建一个条件类型,如果需要该字段,field
类型将为{ required : true }
或{}
类型,否则:
type DomainDefinition<F, M> = {
fields?: {
[K in keyof F]: ({} extends { [P in K]: F[K] } ? {} : { required: true }) & {} // Intersect with other properties as necessary
},
methods?: { [K in keyof M]: M[K] & Function },
}
type User = {
id: string,
name?: string
}
function createDomain<T>(o: DomainDefinition<T, any>) {
return o;
}
export const User = createDomain<User>({
fields: {
id: { required: true },
name: {},
},
});
注意,这将测试可选性(?
修饰符),不会测试可空性(| null | undefined
),具体取决于您的用例,这可能重要也可能不重要
也可能感兴趣的this答案测试了readonly
修饰符。使用它,您还可以添加一个isReadonly
字段:
type IfEquals<X, Y, A, B> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? A : B;
type DomainDefinition<F, M> = {
fields?: {
[K in keyof F]:
({} extends { [P in K]: F[P] } ? {} : { required: true })
& IfEquals<{ [P in K]: F[P] }, { -readonly [P in K]: F[P] }, {}, { isReadonly: true }>
},
methods?: { [K in keyof M]: M[K] & Function },
}
type User = {
id: string,
readonly name?: string
}
function createDomain<T>(o: DomainDefinition<T, any>) {
return o;
}
export const User = createDomain<User>({
fields: {
id: { required: true },
name: { isReadonly: true },
},
});
如果要过滤掉某些属性,例如函数,则必须用过滤后的F
替换所有出现的F
。为了使其更简单,只需定义一个额外的类型别名:
type NonFunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T];
type DomainPropertyHelper<F> = {
[K in keyof F]: ({} extends { [P in K]: F[K] } ? {} : { required: true }) & {} // Intersect with other properties as necessary
};
type DomainDefinition<F, M> = {
fields?: DomainPropertyHelper<Pick<F, NonFunctionPropertyNames<F>>>,
methods?: { [K in keyof M]: M[K] & Function },
}