Typescript 基于泛型修改类型

Typescript modify type based on generic

提问人:nick zoum 提问时间:11/2/2023 最后编辑:nick zoum 更新时间:11/2/2023 访问量:58

问:

问题

有没有办法让类型的泛型修改类型本身?
可以在不创建两个函数的情况下完成吗?
这与 js 功能无关,只是关于让类型匹配。

当我使用泛型调用函数时,我希望返回类型为 。
当我用它调用它时,应该是.
但是,当我用泛型调用它或不提供泛型时,它应该是 .
HTMLInputElement Array<HTMLInputElement>HTMLSelectElementArray<HTMLSelectElement>neverstring

缩小的示例,这不起作用,因为返回类型始终是(尽管 T 具有正确的值):Array<T> | string

type InteractiveElement = HTMLInputElement | HTMLSelectElement;

function getValue<T extends InteractiveElement = never>(): Array<T> | string {
  return null as unknown as Array<T> | string; // 
}

const inputValue = getValue<HTMLInputElement>(); // should be ChangeEvent<HTMLInputElement>
const selectValue = getValue<HTMLSelectElement>(); // should be ChangeEvent<HTMLSelectElement>
const emptyValue = getValue(); // should be string
TypeScript 泛型 重载

评论

0赞 T.J. Crowder 11/2/2023
你用的是什么类型?DOM 的事件只使用 .你使用的是 React 还是类似的?ChangeEventchangeEvent
0赞 katniss 11/2/2023
使用重载:tsplay.dev/N5QaZN
1赞 nick zoum 11/2/2023
@T.J.Crowder是的,我正在使用react,我忘了删除它,我用它替换了它,因为根类型不相关。Array
0赞 T.J. Crowder 11/2/2023
@nickzoum - 是的,如果我们知道它是什么,就整洁一下。 工程。:-)Array

答:

3赞 jcalz 11/2/2023 #1

您可以通过重载来执行此操作,以便首先使用非泛型调用签名:getValue()

function getValue(): string;
function getValue<T extends InteractiveElement>(): Array<T>;
function getValue() {
    return null!
}

const inputValue = getValue<HTMLInputElement>(); // Array<HTMLInputElement>
const selectValue = getValue<HTMLSelectElement>(); // Array<HTMLSelectElement>
const emptyValue = getValue(); // string

或者,您可以让函数返回一个条件类型,该类型检查是否为(这要求条件类型不是分布式的,因此用 + 包装)并返回,如果是,或者如果不是:Tnever[]stringArray<T>

function getValue<T extends InteractiveElement = never>():
    [T] extends [never] ? string : Array<T> {
    return null!
}

const inputValue = getValue<HTMLInputElement>(); // Array<HTMLInputElement>
const selectValue = getValue<HTMLSelectElement>(); // Array<HTMLSelectElement>
const emptyValue = getValue(); // string

无论哪种方式,此示例都无法正确实现,因为 JavaScript 没有实际的函数参数可供操作。但既然你说它是“缩小”的,也许没关系。

Playground 代码链接

评论

0赞 T.J. Crowder 11/2/2023
[T] extends [never]——我必须试着记住这一点。:-)
0赞 nick zoum 11/2/2023
谢谢,这就是我一直在寻找的。我想我必须阅读一些关于条件类型的知识。
1赞 Silvan Bregy 11/2/2023 #2

除了上面的答案之外,这里还有一个使用 type 而不是 .它还使用条件类型,这似乎是这里最合适的方法。undefinednever


type InteractiveElement = HTMLInputElement | HTMLSelectElement;
type EventByValue<T> = T extends undefined ? string : ChangeEvent<T> 

function getValue<T extends InteractiveElement | undefined = undefined>(): EventByValue<T> {
  return null as any
}

const inputValue = getValue<HTMLInputElement>(); //  ChangeEvent<HTMLInputElement>
const selectValue = getValue<HTMLSelectElement>(); // ChangeEvent<HTMLSelectElement>
const emptyValue = getValue(); // string