TypeScript中如何让函数返回字面量类型而非联合类型?
解决TypeScript中createElement函数自动推断元素类型的问题
问题说明
我写了一个动态创建DOM元素的TypeScript函数,但它返回的是HTMLElementTagNameMap的联合类型,没法自动对应到传入标签的具体元素类型。
初始函数代码:
function createElement(type: keyof HTMLElementTagNameMap) { return document.createElement(type) }
调用这个函数时,返回类型是一堆元素类型的联合:
(HTMLElement | HTMLObjectElement | HTMLAnchorElement | HTMLAreaElement | HTMLAudioElement | ... 57 more ... | HTMLVideoElement)
我试过改成下面这种泛型写法:
type valueOf<T> = T[keyof T] function createElement<T extends valueOf<HTMLElementTagNameMap>>(type: keyof HTMLElementTagNameMap) { return document.createElement(type) as T }
注:我其实搞不懂这个函数到底是怎么工作的!
但这种写法必须手动指定泛型类型,才能拿到正确的元素类型:
const div = createElement<HTMLDivElement>('div')
我想要的效果是和原生document.createElement一样,传入标签名就能自动推断出对应的元素类型,比如:
let li = document.createElement('li') // 自动推断为HTMLLIElement
正确实现方式
要让函数自动推断类型,需要把泛型参数和传入的标签名字符串绑定,让返回类型和标签名直接关联。写法如下:
function createElement<T extends keyof HTMLElementTagNameMap>(type: T): HTMLElementTagNameMap[T] { return document.createElement(type) as HTMLElementTagNameMap[T] }
现在调用时,TypeScript会自动根据传入的标签名推断返回类型:
const div = createElement('div') // 类型自动推断为HTMLDivElement const button = createElement('button') // 类型自动推断为HTMLButtonElement
为什么这样可行?
- 泛型
T被约束为HTMLElementTagNameMap的键(也就是合法的HTML标签名字符串类型) - 返回类型直接指定为
HTMLElementTagNameMap[T],也就是该标签对应的具体DOM元素类型 - 这里的
as HTMLElementTagNameMap[T]类型断言是为了让TypeScript明确知道返回值的类型和传入的type参数是对应的,避免编译器报错
内容的提问来源于stack exchange,提问作者Kunal Tanwar
相关产品推荐
相关产品推荐

