我倾向于让您的界面扩展一个映射的条件类型,它本身就是一个函数。这是一个递归类型定义(称为F-bounded quantification),可以让您做一些相当强大(如果令人困惑)的类型约束。例如:
type Restrict<T, U> = { [K in keyof U]: K extends keyof T ? T[K] : never };
type RestrictClient<U> = Restrict<Client, U>;
// okay as desired
interface Okay extends RestrictClient<Okay> {
firstName: string;
lastName: string;
cellNumberFull: string;
}
// error, as desired
interface Extra extends RestrictClient<Extra> {
// ~~~~~
// Types of property 'foo' are incompatible.
// Type 'string' is not assignable to type 'never'.
firstName: string;
lastName: string;
cellNumberFull: string;
foo: string;
}
通过使您的新界面I extends RestrictClient<I>,当且仅当I 可分配给RestrictClient<I>,这意味着如果I 可分配给{[K in keyof I]: K extends keyof Client ? Client[K] : never},这意味着如果@ 的每个键K 987654330@ 存在于Client 中,并且属于相同(或更窄)的类型。
这也给出了以下行为,可能会或可能不会解决您的用例:
// okay to narrow properties
interface Narrowed extends RestrictClient<Narrowed> {
firstName: "specificString";
}
// error to widen properties
interface Widened extends RestrictClient<Widened> {
// ~~~~~~~ <-- number not assignable to string
firstName: string | number;
}
// error to change property to unrelated types
interface Unrelated extends RestrictClient<Unrelated> {
// ~~~~~~~~~ <-- number not assignable to string
firstName: number;
}
如果它与您要查找的内容不完全匹配,您可以更改Restrict 的定义以使其更接近。无论如何,希望这能给你一些想法。祝你好运!
Link to code