簡體   English   中英

TypeScript復雜的通用方法

[英]TypeScript complex generic method

我目前有這種方法

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;

此方法位於.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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM