我不明白为什么泛型函数自动获取泛型类型,而不提供任何东西.

type T<G = Record<string, any>> = {
     id: keyof G
     label: string
     somethingElse?: string
}

此函数返回一个具有特殊属性id的对象,如果没有将source属性传递给该对象,则该对象应该具有类型"random".如果传递source,则返回的id应为source的类型

const element = <ID extends string = 'random'>({ source }: { source?: ID } = {}) =>
    ({
        id: (source || 'random') as ID,
        label: 'Element1',
    }) as const satisfies T  
    // I don't want the return type to be "T", I want what it returns to satisfy "T".
    // as you see I dont provide "somethingElse" key here, so I don't want it in the return type

type Data = { a: string; b: number }

这给出了我想要的确切错误,但仅当我使用变量时:

const el1 = element()                   // el1 gets type { readonly id: "random";  readonly label: "Element1"; }
const el2 = element({source: 'b'})     // el2 gets type { readonly id: "b";  readonly label: "Element1"; }
const el3 = element({source: 'else'})   // el3 gets type { readonly id: "else";  readonly label: "Element1"; }

const b: T<Data>[] = [el, el2, el3]   // el1 and el3 invalid, el2 valid. It is all correct

但是为什么这是有效的,当我直接使用它没有变量?它应该抛出一个错误

const a: T<Data>[] = [element()]   
// No generic or property is provided to it "element()", 
// why the return type of "element()" is { readonly id: keyof Data; readonly label: "Element1"; } ?? 

TypeScript Playground

推荐答案

类型脚本可以是use function return types as inference targets,这意味着generic函数可以通过其返回的上下文类型以及其参数的已知类型来推断其类型参数.在……里面

const a: T<Data>[] = [element()]   

编译器期望[element()]是类型T<Data>[],因此element()是类型T<Data>,因此ID是类型keyof Data,没有错误.


如果您不喜欢这样,并且希望将返回类型not用作推理站点,则可以使用the NoInfer utility type来阻止来自该位置的推理:

const element = <ID extends string = 'random'>({ source }: { source?: ID } = {}) =>
   ({
       id: (source || 'random') as NoInfer<ID>, // <-- here
       label: 'Element1',
   }) as const satisfies T  

在不是从返回类型推断ID的情况下,这应该不会有任何影响,并且您的所有其他示例都是相同的:

const el1 = element()             
// el1 gets type { readonly id: "random";  readonly label: "Element1"; }. 
const el2 = element({source: 'b'})   
// el2 gets type { readonly id: "b";  readonly label: "Element1"; }.
const el3 = element({source: 'else'})   
// el3 gets type { readonly id: "else";  readonly label: "Element1"; }.
const b: T<Data>[] = [el1, el2, el3]   // el1 and el3 invalid, el2 valid. 

但是现在你得到了你的最后一个例子中想要的错误,因为T<Data>上下文不会影响ID.由于ID现在根本没有推理点,它回到了"random"default:

const a: T<Data>[] = [element()]  // error!
// Type '{ readonly id: "random"; readonly label: "Element1"; }' 
// is not assignable to type 'T<Data>'.

Playground link to code

Typescript相关问答推荐

net::BER_RECTION_REUSED和Uncatch使用Axios和TanStack-Query useMutation时未捕获错误(DelivercMutation)

当使用`type B = A`时,B的类型显示为A.为什么当`type B = A时显示为`any `|用A代替?

如何为父类构造函数中的修饰属性赋值?

如何正确地对类型脚本泛型进行限制

具有泛型类型和缺省值的键

如何使用WebStorm调试NextJS的TypeScrip服务器端代码?

为什么我的条件类型不能像我预期的那样工作?

如何将泛型对象作为返回类型添加到类型脚本中

如何使我的函数专门针对联合标记?

如何从扩展接口推断泛型?

布局组件中的Angular 17命名路由出口

如何创建由空格连接的多个字符串的类型

类型脚本-处理值或返回值的函数

如何在Type脚本中创建一个只接受两个对象之间具有相同值类型的键的接口?

带有';的类型脚本嵌套对象可选属性错误满足';

如何调整项目数组,但允许权重影响顺序

覆盖高阶组件中的 prop 时的泛型推理

如何使用动态生成的键和值定义对象的形状?

如何为字符串模板文字创建类型保护

为什么我的 Typescript 函数中缺少 void 隐式返回类型?