typescript - 来自自定义映射类型的中间类型
问题描述
我创建了一个映射类型,用于明确禁止某些对象/接口属性。原因是 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'."
解决方案
您遇到了一个约束,其中 的值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>;
请注意,由于您已经解除了约束 that K extends keyof T
,您可以自由指定T
根本不包含Blocked
键的 a :
type IsThisOkay = DisallowBandC<{foo: string}>;
// equivalent to {foo: string, b?: never, c?: never}
我想这就是你想要的,对吧?
对于第二个问题,您想知道是否可以表示Disallow
没有交集( &
),而不是联合( |
)。答案是肯定的,只要你的意思是最终输出不包含 a&
而不是定义根本不使用交集:
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]
}
这本质上是等价的,除了它是一个映射类型,它遍历Omit<T, K> & Never<K>
. 这些与 相同,K | keyof T
但使用交集的优点是使其成为同态映射类型,其中 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;
}
对我来说看上去很好。好的,希望有帮助;祝你好运!
推荐阅读
- flutter - Flutter 未来函数
- c# - 使用 NLog Layout Renders 将数值记录为数字
- php - PHP WooCommerce NEXT - 同一类别产品的上一个按钮 - 对齐
- python - 多维点之间的最小欧几里得距离路径
- javascript - 查询 mongodb 以获取集合中所有子文档的数组
- python - 为什么要更新所有字典键值,而不仅仅是我指定的键值?
- postgresql - Postgresql 复制生成的列
- javascript - 以下链接后未添加 Javascript 事件侦听器
- python - 在python中将字符串转换为字节
- r - 将 sf POLYGON 转换为字符