[英]Typescript generics does not work with Readonly
Let's have the following simplified example in TypeScript:让我们在 TypeScript 中使用以下简化示例:
type Foo = { name: string } | undefined
function fooWorks<T extends Foo>(input: T) {
return input?.name // ok
}
function fooErrors<T extends Foo>(input: Readonly<T>) {
return input?.name // error
}
Why fooWorks
works, but fooErrors
does not?为什么fooWorks
有效,而fooErrors
无效?
It gives the following error:它给出了以下错误:
Property 'name' does not exist on type
NonNullable
.属性“名称”在类型NonNullable
上不存在。
The problem is, that the TypeScript compiler does not understand the subtle type narrowing here and throws a compile-time error as stated here (though, I am not 100% sure about how helpful this blog post is for you).问题是,该打字稿编译器不明白其中的奥妙型这里收窄,并抛出作为一个说明编译时错误在这里(虽然我不是100%地肯定这个博客帖子是如何帮助别人是你)。
Removing undefined
from Foo
works:从Foo
删除undefined
有效:
type Foo = { name: string }
function fooWorks<T extends Foo>(input: T) {
return input?.name
}
function fooErrors<T extends Foo>(input: Readonly<T>) {
return input?.name
}
Or you can add the NonNullable
type excluding null
and undefined
from T
, which results in input
being { name: string }
:或者,您可以添加从T
排除null
和undefined
的NonNullable
类型,这会导致input
为{ name: string }
:
type Foo = { name: string } | undefined
function fooWorks<T extends Foo>(input: T) {
return input?.name
}
function fooErrors<T extends Foo>(input: Readonly<NonNullable<T>>) {
return input.name
}
The following will preserve the Readonly
type and undefined
as desired:以下将根据需要保留Readonly
类型和undefined
:
function fooErrors<T extends Readonly<Foo>>(input: T) {
return input?.name // works
}
Note: we set Readonly
in the generic constraint and don't wrap it around the parameter type.注意:我们在泛型约束中设置了Readonly
并且不将其包装在参数类型周围。
The reason, why fooErrors<T extends Foo>(input: Readonly<T>)
causes issues is: TypeScript does not process unresolved generic type parameters (like T
) further. fooErrors<T extends Foo>(input: Readonly<T>)
导致问题的原因是:TypeScript 不会进一步处理未解析的泛型类型参数(如T
)。 Readonly
essentially is a mapped type . Readonly
本质上是一种映射类型。 So in the function body, input
has type { readonly [P in keyof T]: T[P]; }
所以在函数体中, input
类型为{ readonly [P in keyof T]: T[P]; }
{ readonly [P in keyof T]: T[P]; }
, which unfortunately is not assignable back to T
and its constraint Foo
. { readonly [P in keyof T]: T[P]; }
,不幸的是不能分配回T
及其约束Foo
。 From the compiler's perspective property name
on the parameter cannot be found anymore.从编译器的角度来看,无法再找到参数上的属性name
。
This seems to be a limitation of type aliases.这似乎是类型别名的限制。
interface Foo { name: string }
function fooWorks<T extends Foo>(input?: T) {
return input?.name // ok
}
function fooErrors<T extends Foo>(input?: Readonly<T>) {
return input?.name // error
}
Behaves as expected.行为符合预期。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.