Typescript泛型无法与Readonly一起使用

8

让我们以 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
}

为什么fooWorks可以正常工作,而fooErrors不能?
3个回答

2
以下代码将会保留所需的 Readonly 类型和 undefined 值:
function fooErrors<T extends Readonly<Foo>>(input: T) {
    return input?.name // works
}

注意:我们在通用约束条件中设置了Readonly,并没有将其包装在参数类型周围。 < p > fooErrors<T extends Foo>(input: Readonly<T>)导致问题的原因是:TypeScript不能进一步处理未解决的泛型类型参数(如T)。Readonly 本质上是一个映射类型。因此,在函数体中,input的类型为{ readonly [P in keyof T]: T[P]; },不幸的是这个类型不能被重新赋值给T和它的约束Foo。从编译器的角度来看,参数上的name属性再也找不到了。

游乐场代码


我无法更改代码,因为真正的代码在第三方库(react)中。(这只是为了演示目的而大大简化的例子。)您能否提供一些参考或问题,其中指定/跟踪了行为? - TN.
https://github.com/microsoft/TypeScript/issues/28884 是泛型未被进一步解释的一个例子。 https://github.com/microsoft/TypeScript/issues/13995 是另一个更为突出的例子(后者专注于联合缩小)。 - bela53
1
感谢您提供问题链接! - TN.

1
它会给出以下错误:
属性“name”在类型“NonNullable”上不存在。
问题是,TypeScript编译器无法理解此处微妙的类型缩小,并在编译时抛出错误,如此处所述(尽管我不确定这篇博客对您有多大帮助)。
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
}

或者你可以添加 NonNullable类型,排除nullundefined,从T中获得,这将导致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
}

我试图阅读这个链接,但是出现了“5xx糟糕!Medium发生了一些问题。”的错误提示。 - TN.
重试,我觉得帖子中的“不理解这里微妙的类型缩小并抛出编译时错误”指的是不同的事情:“filter”没有返回不同的类型。 - TN.
找到一份易于理解的描述这种行为的解释相当困难(至少对我来说是这样)。我会继续寻找。 - pzaenger

0

这似乎是类型别名的限制。

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
}

表现如预期。


很不幸,{ name?: string } != { name: string } | undefined。这是已知的问题吗? - TN.
fooErrors<T extends { name: string } | undefined>(input: Readonly<T>) 不起作用。 - TN.
抱歉,我稍微误读了类型。我已经更新了它。 已知的限制在这个问题中有很好的概述:https://dev59.com/5loU5IYBdhLWcg3wqIK0 - Neal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接