我创建了一个映射类型,以明确禁止某些对象/接口属性。原因是Typescript的多余属性检查仅在直接分配对象文字时才适用,而不是在首次将其分配给变量时才适用。
请参阅“多余的属性检查” https://www.typescriptlang.org/docs/handbook/interfaces.html
我有一些函数带有一个对象,该对象不能包含某些特定的已知属性。同样,这可以通过传入对象文字来解决,但是下一个开发人员很容易忽略它,因此我认为将其完全阻止会很好(我确实意识到我应该检查对象是否有多余的道具)。运行时,但我的问题仅与TS有关。
我的主要问题是是否可以编写Disallow
类型,以便我可以从中创建中间类型,例如DisallowBandC
?
第二个问题是,是否可以在不创建两种类型的并集的情况下实现Disallow
?也欢迎进行其他简化。
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
type Never<T, K extends keyof T> = { readonly [P in K]?: never };
// Can this be achieved without a union?
type Disallow<T, K extends keyof T> = Omit<T, K> & Never<T, K>;
interface Stuff {
readonly a: string;
readonly b?: number;
readonly c: string | null;
readonly d: null;
readonly e?: null;
readonly f?: undefined;
readonly g: string;
}
type Blocked = 'b' | 'c'
// This works
export type Disallowed = Disallow<Stuff, Blocked>;
// This does not work:
export type DisallowBandC<T> = Disallow<T, Blocked>;
// TS Error:
// "Type 'Blocked' does not satisfy the constraint 'keyof T'.
// Type '"b"' is not assignable to type 'keyof T'."
答案 0 :(得分:2)
您遇到了一个约束,其中K
的值必须是T
的键。要解除此约束,可以进行以下更改:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
// don't need T at all here
type Never<K extends keyof any> = { readonly [P in K]?: never };
// don't need to restrict K to keys of T
type Disallow<T, K extends keyof any> = Omit<T, K> & Never<K>;
现在可以使用:
export type DisallowBandC<T> = Disallow<T, Blocked>;
请注意,由于您已经解除了K extends keyof T
的约束,因此可以自由指定根本不包含T
键的Blocked
:
type IsThisOkay = DisallowBandC<{foo: string}>;
// equivalent to {foo: string, b?: never, c?: never}
我想这就是你想要的,对吧?
对于第二个问题,您想知道是否可以不使用intersection(Disallow
)而不是union(&
)来代表|
。答案是肯定的,只要您的意思是最终输出不包含&
,并且不表示定义根本不使用交集:
type Disallow<T, K extends keyof any> = {
[P in keyof (Omit<T, K> & Never<K>)]: P extends K ? never : P extends keyof T ? T[P] : never
};
或者等效地,这很明显地表明您肯定在定义中使用了相同的相交类型:
type Disallow<T, K extends keyof any> = {
[P in keyof (Omit<T, K> & Never<K>)]: (Omit<T, K> & Never<K>)[P]
}
这实际上是等效的,只是它是mapped type,它在Omit<T, K> & Never<K>
的键上进行迭代。它们与K | keyof T
相同,但是使用交集具有使它成为homomorphic映射类型的优点,其中TypeScript保留readonly
的键的T
和任何键的可选性质。我们确保:
type TryItOut = DisallowBandC<Stuff>;
此检查为
type TryItOut = {
readonly a: string;
readonly d: null;
readonly e?: null | undefined;
readonly f?: undefined;
readonly g: string;
readonly b?: undefined;
readonly c?: undefined;
}
对我很好。好的,希望能有所帮助;祝你好运!