TypeScript:即使在缩小范围后也不能分配给类型的对象
我有一个函数,它接收一个对象并缩小它的范围,以检查它是否包含一个特定类型的属性TypeScript:即使在缩小范围后也不能分配给类型的对象,typescript,Typescript,我有一个函数,它接收一个对象并缩小它的范围,以检查它是否包含一个特定类型的属性foo,即string 在狭窄的分支中,我希望input可以分配给ObjectWithFooStringProp,但它不是出于某种原因。为什么会这样 type DictionaryLike = { [index: string]: unknown; }; type ObjectWithFooStringProp = { foo: string; }; const getObjectWithFooSt
foo
,即string
在狭窄的分支中,我希望input
可以分配给ObjectWithFooStringProp
,但它不是出于某种原因。为什么会这样
type DictionaryLike = {
[index: string]: unknown;
};
type ObjectWithFooStringProp = {
foo: string;
};
const getObjectWithFooStringProp = (
input: DictionaryLike,
): ObjectWithFooStringProp | null => {
if (typeof input.foo === 'string') {
input.foo; // Type is `string` ✅
// Unexpected error ❌
// Property 'foo' is missing in type 'DictionaryLike' but required in type 'ObjectWithFooStringProp'.
return input;
// Workaround:
// return { foo: input.foo };
} else {
return null;
}
};
我在上面的例子中提到了一种变通方法,但是我有一个现实世界的用例,这种变通方法是不可能的,所以我很想弄清楚为什么TypeScript会以这种方式运行。我不知道为什么这不起作用,但目前,您可以使用一个专用的类型保护程序来正确地缩小类型
type DictionaryLike = {
[index: string]: unknown;
};
type ObjectWithFooStringProp = {
foo: string;
};
const isObjectWithFooStringProp = (input: DictionaryLike): input is ObjectWithFooStringProp =>
typeof input.foo === 'string'
const getObjectWithFooStringProp = (
input: DictionaryLike,
): ObjectWithFooStringProp | null => {
if (isObjectWithFooStringProp(input)) {
return input;
} else {
return null;
}
};
防护装置通常影响应用于整个对象的属性类型,而不是整个对象。一个值得注意的例外是对Description属性的检查确实会更改包含对象的类型的有区别的联合。但在您的护理中,我们没有歧视工会,因此检查实际上对
输入没有任何影响
唯一的解决方法是在检查后使用自定义类型保护更改输入的类型
:
type DictionaryLike = {
[index: string]: unknown;
};
type ObjectWithFooStringProp = {
foo: string;
};
function hasStringProp<K extends string>(o: DictionaryLike, key: K) : o is Record<K, string>{
return typeof o[key] === 'string';
}
const getObjectWithFooStringProp = (
input: DictionaryLike,
): ObjectWithFooStringProp | null => {
if (hasStringProp(input, 'foo')) {
input.foo; // Type is `string` ✅
// ok now
return input;
// Workaround:
// return { foo: input.foo };
} else {
return null;
}
};
type DictionaryLike={
[索引:字符串]:未知;
};
类型ObjectWithFooStringProp={
foo:string;
};
函数hasStringProp(o:DictionaryLike,key:K):o是记录{
返回o[key]=“string”的类型;
}
常量getObjectWithFooStringProp=(
输入:字典式,
):ObjectWithFooStringProp | null=>{
if(hasStringProp(输入'foo')){
input.foo;//类型为'string`✅
//好了
返回输入;
//解决方法:
//返回{foo:input.foo};
}否则{
返回null;
}
};
您可以使用返回输入利用类型转换代码>
type DictionaryLike={
[键:字符串]:未知
}
类型ObjectWithFooStringProp={
foo:string
}
常量getObjectWithFooStringProp=(
输入:DictionaryLike
):ObjectWithFooStringProp | null=>{
if(typeof input.foo=='string'){
input.foo//类型为'string`✅
//无误✅
返回输入
//解决方法:
//返回{foo:input.foo};
}否则{
返回空
}
}
谢谢!你知道有没有人建议在TypeScript中解决这个问题,这样对象类型本身也会改变?如果不是的话,也许我会提交一份。我故意避免在这里使用用户定义的类型保护,因为TypeScript中还有另一个设计限制:用户定义的类型保护没有任何类型检查@OliverJosephAsh并没有真正意识到这样一个提议。并不意味着一个人不存在。我知道使用类型保护缩小对象
或未知
是一个问题,但现在找不到它嘿,小世界!:-)我故意避免在这里使用用户定义的类型保护,因为TypeScript中有一个设计限制:用户定义的类型保护没有任何类型检查。然而,这并不是说这个答案是错误的,只是它不太符合我的要求。我相信这会帮助很多遇到这种情况的人。谢谢不幸的是,类型转换丢失了一些类型检查。