【发布时间】:2017-12-18 11:51:44
【问题描述】:
我知道在 TypeScript 中我可以声明如下函数:
function doSomething<E extends Element>(el : E) : E;
function doSomething<N extends keyof ElementTagNameMap>(selector : N) : ElementTagNameMap[N];
function doSomething<E extends Element>(el : E | keyof ElementTagNameMap) {
if(typeof el === 'string') {
return document.createElement(el) as Element as E;
} else {
return el;
}
}
它们的用法将被正确输入
doSomething(document.querySelector('option')!) // return value typed as HTMLOptionElement
doSomething(new Image()); // return value typed as HTMLImageElement
doSomething('input'); // return value typed as HTMLInputElement
如何使用泛型类的构造函数实现相同的功能?
class Some<E extends Element> {
public element : E;
constructor(el : E | keyof ElementTagNameMap) {
if(typeof el === 'string') {
this.element = document.createElement(el) as Element as E;
} else {
this.element = el;
}
}
}
new Some(document.querySelector('option')!); // Works, type is Some<HTMLOptionElement>
new Some(new Image()); // Works, type is Some<HTMLImageElement>
但我似乎无法让以下工作:
new Some('input'); // Type is Some<Element> (the fallback) instead of Some<HTMLInputElement>
(当然,使用 new Some<HTMLInputElement>('input') 可以,但如果我已经有 ElementTagNameMap 为我执行此操作,我不应该显式输入。)
我已经尝试向构造函数添加重载,就像我在上一个示例中对函数所做的那样:
constructor<N extends keyof ElementTagNameMap>(el : N) : Some<ElementTagNameMap[N]>;
// ⇒ Error: Type parameters cannot appear on a constructor function
constructor<N extends keyof ElementTagNameMap>(this : Some<ElementTagNameMap[N]>, el : N);
// ⇒ Error: A constructor cannot have a `this` parameter
我知道我可以创建一个辅助函数createSome:
function createSome<E extends Element>(el : E) : Some<E>;
function createSome<N extends keyof ElementTagNameMap>(selector : N) : Some<ElementTagNameMap[N]>;
function createSome<E extends Element>(el : E | keyof ElementTagNameMap) {
return new Some(el);
}
createSome(document.querySelector('option')!); // Works: type is Some<HTMLOptionElement>
createSome(new Image()); // Works: type is Some<HTMLImageElement>
createSome('input'); // Works too now: type is Some<HTMLInputElement>
但是没有办法直接实现这一点吗?我需要添加一个运行时构造(辅助函数)来获得特定的编译时行为(类型推断),这似乎违反直觉。
【问题讨论】:
-
能否详细说明您的问题?我是否理解正确,您不喜欢代码:
new Some(new Image());创建Some<Element>类型的实例,而不是new Some<HTMLImageElement>的事实? -
@MarkDolbyrev 是的。或者更具体地说:如何向构造函数添加重载,其工作方式与我给出的函数示例相同。
-
@MarkDolbyrev 我误读了您的评论:实际上,
new Some(new Image())的类型符合预期,我想正确推断出new Some('img')(通过keyof ElementTagNameMap)。 -
我用您可能更喜欢的东西更新了我的解决方案;看看吧。
-
@jcalz 太棒了。我希望我能再次投票……
标签: typescript generics