【问题标题】:Typescript how to infer Literal types or string打字稿如何推断文字类型或字符串
【发布时间】:2020-12-22 14:36:21
【问题描述】:

所以我试图根据传入的参数获取一个对象。 我发现了这个问题,它与我所追求的非常接近。 TypeScript function return type based on input parameter 但是,我希望函数也能够接受字符串,并且当传入的参数不是字面量类型时,它会推断any or unknown

让我把我的意思写在代码里。

interface Circle {
    type: "circle";
    radius: number;
}

interface Square {
    type: "square";
    length: number;
}

type TypeName = "circle" | "square" | string; 

type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    unknown;

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]  {
    ...
}

请注意,TypeName 具有文字类型和字符串的联合类型。 我希望看到的是,当我使用该类型时,我将能够根据参数推断返回类型。例如:

const circle = getItems('circle'); // infers: Circle
const something = getItems('unknown'); // infers: unknown

以上都很好。但是,我无法让 IDE 建议这些选项。 我希望看到以下选项:'circle' | 'square' | string

有可能吗?

【问题讨论】:

  • 如果您删除了TypeName 中的| string 选项,它应该可以在您的IDE 中使用。或者你可以添加类似type TypeName = "circle" | "square" | "unknown";
  • 是的。但是,当我将字符串“未知”放入参数中时,它会出现类型错误。我希望该函数能够推断出unknown 类型。
  • this codesandbox 之后似乎没有类型错误,如果您将鼠标悬停在被调用的函数上,它的类型正确,我是否遗漏了什么?
  • 感谢@Stutje 的回答。示例中的类型为type TypeName = "circle" | "square" | "unknown";。但是,我想要type TypeName = "circle" | "square" | string;,实际的string 类型。其背后的原因是,如果类型不是我指定的 Literal Type,我想按原样使用类型值。

标签: typescript typescript-typings typescript-generics


【解决方案1】:

不,这是不可能的,因为string 是字符串文字的超级类型,所以

type TypeName = "circle" | "square" | string; 

没有什么不同
type TypeName = string; 

但是,您可以使用函数重载来实现您的目标

type TypeName = "circle" | "square"
type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    never

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]
function getItems(type: string) : unknown[]
function getItems(type: string) {
  // implementation comes here
}

不管怎样,这是一个新的技巧

type TypeName = "circle" | "square" | {} & string; 

type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    unknown;

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]  {
    ...
}

自己试试

【讨论】:

  • 感谢您抽出宝贵时间回答@Austraras。但是,该解决方案看起来并不奏效。我创建了一个codepen here
  • 你错过了第二次超载并直接进入实施
【解决方案2】:

您可以使用重载和一些条件实用程序类型来做到这一点:

interface Circle {
    type: "circle";
    radius: number;
}

interface Square {
    type: "square";
    length: number;
}


type KnownObject = Circle | Square
type IsKnownTypeName<T extends string, U = KnownObject> = U extends { type: T } ? T : never
type ObjectForType<T extends string, U = KnownObject> = U extends { type: T } ? U : never

function getItems<T extends string>(type: IsKnownTypeName<T>) : ObjectForType<T>[]
function getItems<T extends string>(type: T) : any[]
function getItems<T extends string>(type: T) : any[] {
    return []
}

const circle = getItems('circle'); // infers: Circle
const something = getItems('unknown'); // infers: any

【讨论】:

    猜你喜欢
    • 2018-06-09
    • 1970-01-01
    • 2021-06-08
    • 1970-01-01
    • 2019-06-26
    • 2020-04-02
    • 2020-12-20
    • 2016-08-03
    • 2019-04-10
    相关资源
    最近更新 更多