传递给函数时对象中键的打字稿缩小
Typescript narrowing of keys in objects when passed to function
为什么 TypeScript 不将对象成员的类型缩小应用到对象类型本身,以便它可以传递给另一个需要缩小类型的函数?这怎么可能 fixed/circumvented 而不会失去类型安全性?
最小示例:
type A = { key: string | null};
type B = {key: string};
function func(a: B) {};
const a: A = {key:'abcd'};
if(typeof(a.key)==='string') {
a.key // has (narrowed) type 'string'
func(a); // still does not work
}
错误信息是:Types of property 'key' are incompatible. Type 'string | null' is not assignable to type 'string'.
使用类型保护:https://www.typescriptlang.org/docs/handbook/advanced-types.html#typeof-type-guards
type A = { key: string | null};
type B = {key: string};
function func(a: B) {};
const a: A = {key:'abcd'};
const isB = (foo: A | B): foo is B => typeof a.key === "string";
if(isB(a)) {
a.key
func(a);
}
这最终是一种 design limitation of TypeScript. It does not use type guards on an object's properties to narrow the object itself, except in the particular case where the object is a discriminated union 类型...而在您的情况下,A
根本不是一个联合体,更不用说一个受歧视的联合体了。
我会为你的情况做这个的方法是引入一个 user-defined type guard function 它明确地执行你期望的缩小:你传入一个带有 key
属性 的对象, return true
或 false
取决于此对象是否有效 B
:
const isB = (x: { key: any }): x is B => typeof x.key === "string";
那你就用它:
if (isB(a)) {
func(a); // okay
}
这与您的代码(提供或接受函数调用)本质上是相同的逻辑,但编译器现在可以识别您的意图。好的,希望有所帮助;祝你好运!
我很好奇并找到了缩小对象 属性 的方法。它并没有缩小到 B 类型,但是 Typescript 是一种具有结构类型的语言,因此该解决方案非常有效。
const isPropString = <P extends string, T extends Record<P, T[P]>>(
prop: P,
object: T,
): object is T & Record<P, string> => {
return typeof object[prop] === 'string';
};
如果您想根据给定类型缩小对象的任何 属性 怎么办? @gwin-pin 有开胃菜,但这里是:
const isValidPropType = <T extends Record<P, T[P]>, P extends keyof T, Z extends T[P]>(
object: T,
prop: P,
typeofParam: Z
): object is T & Record<P, Z> => {
return typeof object[prop] === typeof typeofParam;
};
TS Playground 使用原题。
为什么 TypeScript 不将对象成员的类型缩小应用到对象类型本身,以便它可以传递给另一个需要缩小类型的函数?这怎么可能 fixed/circumvented 而不会失去类型安全性?
最小示例:
type A = { key: string | null};
type B = {key: string};
function func(a: B) {};
const a: A = {key:'abcd'};
if(typeof(a.key)==='string') {
a.key // has (narrowed) type 'string'
func(a); // still does not work
}
错误信息是:Types of property 'key' are incompatible. Type 'string | null' is not assignable to type 'string'.
使用类型保护:https://www.typescriptlang.org/docs/handbook/advanced-types.html#typeof-type-guards
type A = { key: string | null};
type B = {key: string};
function func(a: B) {};
const a: A = {key:'abcd'};
const isB = (foo: A | B): foo is B => typeof a.key === "string";
if(isB(a)) {
a.key
func(a);
}
这最终是一种 design limitation of TypeScript. It does not use type guards on an object's properties to narrow the object itself, except in the particular case where the object is a discriminated union 类型...而在您的情况下,A
根本不是一个联合体,更不用说一个受歧视的联合体了。
我会为你的情况做这个的方法是引入一个 user-defined type guard function 它明确地执行你期望的缩小:你传入一个带有 key
属性 的对象, return true
或 false
取决于此对象是否有效 B
:
const isB = (x: { key: any }): x is B => typeof x.key === "string";
那你就用它:
if (isB(a)) {
func(a); // okay
}
这与您的代码(提供或接受函数调用)本质上是相同的逻辑,但编译器现在可以识别您的意图。好的,希望有所帮助;祝你好运!
我很好奇并找到了缩小对象 属性 的方法。它并没有缩小到 B 类型,但是 Typescript 是一种具有结构类型的语言,因此该解决方案非常有效。
const isPropString = <P extends string, T extends Record<P, T[P]>>(
prop: P,
object: T,
): object is T & Record<P, string> => {
return typeof object[prop] === 'string';
};
如果您想根据给定类型缩小对象的任何 属性 怎么办? @gwin-pin 有开胃菜,但这里是:
const isValidPropType = <T extends Record<P, T[P]>, P extends keyof T, Z extends T[P]>(
object: T,
prop: P,
typeofParam: Z
): object is T & Record<P, Z> => {
return typeof object[prop] === typeof typeofParam;
};
TS Playground 使用原题。