我目前有这个方法
create<T extends ElementType | string>(type: T): Element<T>;
它使用
export type ElementType = 'ExtensionElements' | 'Documentation';
export type Element<T> =
T extends 'ExtensionElements' ? ExtensionElements :
T extends 'Documentation' ? Documentation :
GenericElement;
此方法在 a 中.d.ts
,它保证结果始终是类型化的,因此
const e1 = obj.create('ExtensionElements');
^^ type is ExtensionElements
const e2 = obj.create('Documentation');
^^ type is Documentation
const e3 = obj.create('Other');
^^ type is GenericElement
现在,我想让这个方法的用户扩展可能的类型选择,例如
type CustomElementType = 'Other' | ElementType;
type CustomElement<T> =
T extends 'Other' ? CustomOtherElement : Element<T>;
const e4 = obj.create<CustomElementType, CustomElement>('Other');
^^ type is CustomOtherElement
然而,这似乎不能正常工作,因为我总是收到所有类型的联合,而且我不能使用任意字符串。
你对我如何实现这个有任何其他想法吗?
您可以使用接口从字符串类型映射到真实类型。由于接口是开放式客户端,因此可以使用模块扩充来添加额外的选项:
// create.ts
export declare let obj: {
create<T extends ElementType | string>(type: T): Element<T>;
}
type ExtensionElements = { e: string }
type Documentation = { d: string }
type GenericElement = { g: string }
export type ElementType = 'ExtensionElements' | 'Documentation';
export interface ElementMap {
'ExtensionElements': ExtensionElements;
'Documentation': Documentation;
}
export type Element<T extends string> = ElementMap extends Record<T, infer E> ? E :
GenericElement;
const e1 = obj.create('ExtensionElements'); // ExtensionElements
const e2 = obj.create('Documentation'); // Documentation
const e3 = obj.create('Else'); //GenericElement
// create-usage.ts
import { obj } from './create'
type CustomOtherElement = { x: string }
declare module './create' {
export interface ElementMap {
'Other': CustomOtherElement
}
}
const e4 = obj.create('Other'); // CustomOtherElement
如果要进行范围扩展,则需要一个额外的函数来更改用于将字符串映射到对象类型的接口。这个方法可以只返回当前对象作为预期结果(因为类型在运行时无关紧要,没有什么需要不同)
// create.ts
interface Creator<TMap = ElementMap>{
create<T extends keyof TMap | string>(type: T): Element<TMap, T>;
extend<TMapExt extends TMap>(): Creator<TMapExt>
}
export declare let obj: Creator
type ExtensionElements = { e: string }
type Documentation = { d: string }
type GenericElement = { g: string }
import { obj, ElementMap } from './create'
type CustomOtherElement = { x: string }
export type ElementType = 'ExtensionElements' | 'Documentation';
export interface ElementMap {
'ExtensionElements': ExtensionElements;
'Documentation': Documentation;
}
export type Element<TMap, T extends PropertyKey> = TMap extends Record<T, infer E> ? E : GenericElement;
const e1 = obj.create('ExtensionElements'); // ExtensionElements
const e2 = obj.create('Documentation'); // Documentation
const e3 = obj.create('Else'); //GenericElement
// create-usage.ts
export interface CustomElementMap extends ElementMap {
'Other': CustomOtherElement
}
const customObj = obj.extend<CustomElementMap>()
const e4 = customObj.create('Other'); // CustomOtherElement
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句