TypeScript:从 Enum 键入接口,可选但至少 1

TypeScript: Key in interface from Enum, Optional but at least 1

我想为具有 userId 或 customerId 的对象创建一个 接口 。 要么一个,一个。

key 应该由枚举定义(因此命名总是相同的)。

我是这样用的,来自另一个例子:

export enum EId {
  userId = 'userId',
  customerId = 'customerId',
}

export type IIdParam = {
  [key in EId]: string;
};

export interface IIdParamString extends IIdParam {
  paramString: string;
}

最后我想要这个对象:

  const params: IIdParamString = {
    userId: String('1234'),
    paramString: 'limit',
  };

但我得到一个错误:当 [key in EId] 不是可选的时,它会抱怨它需要 userId 和 customerId,如果不是可选的,则...

也许这不是我想要的正确方法。 我想枚举中的值实际上不需要密钥,但我不能更好地从示例中抽象它。

考虑这个例子:


export enum EId {
    userId = 'userId',
    customerId = 'customerId',
}

type AtLeastOne<Obj, Keys = keyof Obj> = Keys extends keyof Obj ? Record<Keys, string> : never

// credits goes to 
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> =
    T extends any
    ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;

type StrictUnion<T> = StrictUnionHelper<T, T>

export type IIdParamString =
    & StrictUnion<AtLeastOne<typeof EId>>
    & {
        paramString: string;
    }

/**
 * Ok
 */
const params: IIdParamString = {
    userId: '1234',
    paramString: 'limit',
};

/**
 * Expected errors
 */
const params2: IIdParamString = {
    paramString: 'limit',
};
const params3: IIdParamString = {
    userId: '1234',
    customerId: 'sdf',
    paramString: 'limit',
};

AtLeastOne - 你可以找到完整的解释

StrictUnion - 你可以找到完整的解释 。此实用程序与您所做的 never 有相似的技巧。

Is my approach in general conventional to my problem, to make sure it is either this or that

是的,你的方法没问题。但我建议你使用有区别的工会。它们也被称为 tagged unions。例如参见 [​​=21=]。您可能已经注意到,每个工会都有自己的 tag/flag/marker。它有助于编译器区分它们。

Could it be an interface ? Unfortunately - no. It could be only type, because interface can extends only statically known type. See example:

// An interface can only extend an object type or intersection of object types with statically known members.
export interface IIdParamString extends StrictUnion<AtLeastOne<typeof EId>> { // error
    paramString: string;
}

关于你最后一个问题,我不确定我是否理解。 您可以更新您的问题或(更好的)选项以单独询问。