在TypeScript中,我可以定义以下类型:
interface FooNameMapping {
Bar: {bar: string};
Baz: {baz: number};
}
我可以在签名中使用的键和映射类型:
function mapped<K extends keyof FooNameMapping>(arg: K): FooNameMapping[K] {
return '' as any;
}
并致电如下:
let x = mapped('Bar'); //typed as {bar: string}
但是,这仅适用于从字符串参数映射的类型。有什么方法可以为从另一种类型映射的类型做类似的事情吗?
换句话说,我有以下重载:
interface EnumeratorConstructor {
new(col: Excel.Actions): Enumerator<Excel.Action>;
new(col: Excel.AddIns | Excel.AddIns2): Enumerator<Excel.AddIn>;
new(col: Excel.AllowEditRanges): Enumerator<Excel.AllowEditRange>;
new(col: Excel.Areas | Excel.Ranges | Excel.Range): Enumerator<Excel.Range>;
new(col: Excel.Borders): Enumerator<Excel.Border>;
}
我能否以某种方式创建一个从Excel.Actions
映射到Excel.Action
的类型,并在单个重载中使用该类型?
答案 0 :(得分:1)
据我所知,目前没有非hacky方法可以做到这一点,并使自动推理正常工作。 TypeScript目前缺少type-level functions or type families,这是您直接实现此功能所需的。 TypeScript有一个typeof
运算符,如果extended适用于任意表达式,尤其是function application,则可以满足您的目的。
你现在可以做的是做一个这样的类型:
interface Example {
a: {from: string, to: number};
b: {from: number, to: string};
}
declare function typeMapping<K extends keyof Example>(x: Example[K]['from']): Example[K]['to'];
但问题是K
不会自动推断为'a'
或'b'
,但除非您明确指定,否则将始终只是'a'|'b'
:
let str: string;
str = typeMapping(123); // error, return value is string|number
str = typeMapping<'b'>(123); // okay, but need to specify 'b'
str = typeMapping<'a'>(123); // error, 1 is not a string
但这比使用函数重载要糟糕得多。
执行此操作的hacky方法是使用declaration merging来扩充您用作函数输入的内容的类型,并明确地为它们提供输出类型的幻像属性。例如:
import * as Excel from 'excel'; // guessing at location
// add phantom property
declare module 'excel' {
interface Actions {
__outputType: Excel.Action
}
interface AddIns {
__outputType: Excel.AddIn
}
interface AddIns2 {
__outputType: Excel.AddIn
}
interface AllowEditRanges {
__outputType: Excel.AllowEditRange
}
// ... etc
}
type Inputs = Excel.Actions | Excel.AddIns | Excel.AddIns2 | Excel.AllowEditRanges // ...
// here's the function now
declare function constructEnumerator<I extends Inputs>(i: I): Enumerator<I['__outputType']>;
declare let actions: Excel.Actions;
const ret = constructEnumerator(actions); // returns Enumerator<Excel.Action> as desired
这一切都可以正常工作,但是你可能会发现自己有TypeScript抱怨你用来创建任何输入类型的对象文字中缺少__outputType
,所以你需要处理那个(例如,文字之后的as Excel.Actions
)。值得吗?
那么,你是多么迫切需要这个?除非TypeScript中出现类型级函数,否则可以处理重载或特定于较少的类型?或者模块扩充是否会成为可行的方法?我想,这取决于你。
无论如何,希望有所帮助;祝你好运!