Typescript条件验证取决于字段的可空性

Typescript条件验证取决于字段的可空性,typescript,Typescript,我有以下代码: 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

我有以下代码:

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: {},
  },
});
我试图验证传递给某个字段的createDomain方法的定义对象中所需的键是否具有一个值,该值与它在此基于的类型的requiredness(用户)相匹配;最好是在编译时

我有一种感觉,条件类型可能有助于这样做,但我找不到一种基于需求的方法。具体地说,我试图约束以下要求:

如果该字段不可为空,则为true, 如果是,则为false或未定义 任何提示?

使用定义为示例的类型,我们可以创建一个条件类型,其中如果字段是必需的,则字段类型将为{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: {},
    },
});
如果要过滤掉某些属性,例如函数,则必须将所有出现的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 },
}

这是一个很好的答案,谢谢。不过,我还有一个问题;你的建议按原样运作。但是,每当我尝试用页面上定义的非功能属性名称将[K in keyof]替换为[K in NonFunctionPropertyNames]时,它就会失败。条件测试仅在发生该变化时为阴性。“你知道为什么吗,幸运的是?”Pierre添加了代码,使其能够与过滤一起工作
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 },
}