首页 > 解决方案 > Typescript 通用函数,以便类型推断和代码提示起作用

问题描述

这是我需要在 Typescript 中定义的函数调用

gen(settings: ISettings, enabled?: object, maps?: object): (v: string) => string;

设置在哪里:

interface ISettings {
    mods: string[];
    states: string[];
}

但是 中的数组值ISettings实际上与函数调用中的另外两个参数有关:enabledmap

也许举个例子会更好理解。

gen({
        mods: ['one', 'two'],
        states: ['init', 'final']
    }, {
        one: true,
        init: true
    }, {
        one: 'first',
        two: 'second',
        final: 'end'
    }
);

如您所见:

这是我得到的代码,但它不起作用。我希望代码完成在第二个和第三个参数对象中建议对象键,因为它们与第一个参数对象中的那些数组相关。

interface ISettings<TMods extends object, TStates extends object> {
    mods: Array<keyof TMods & string>;
    states: Array<keyof TStates & string>;
    [other: string]: any;
}

function gen<
    TMods extends object = {},
    TStates extends object = {}
>(
    settings: string | ISettings<TMods, TStates>,
    enabled: Partial<Record<keyof (TMods & TStates), boolean>> = {},
    maps: Partial<Record<keyof (TMods & TStates), string>> = {}
): string {
    //function doesn't return anything yet
    return '';
}

gen({
    mods: ['one', 'two'],
    states: ['disabled', 'fixed']
}, {
    one: true,
    disabled: true
}, {
    one: 'first',
    two: 'second',
    fixed: 'static'
});

从提议的类型可以看出,enabled和参数可以定义对象maps中提供的两个字符串数组组合的任何成员子集(或完整) 。settings这两个对象可以有重叠的成员。

Partial<Record<keyof (TMods & TStates), ...>>

注意:此代码基本上是尝试为同名的 npm 库的suit-cx.d.ts和文件定义代码,如果您熟悉它们的话。bem-classnames.d.ts

标签: typescript

解决方案


稍微简化类型,以便编译器只需将键推断为字符串文字类型(而不是作为另一个未知对象的键),编译器可以在编写第二个和第三个参数时提供建议:

interface ISettings<TModsKeys extends string, TStatesKeys extends string> {
    mods: Array<TModsKeys>;
    states: Array<TStatesKeys>;
    [other: string]: any;
}

function gen<
    TModsKeys extends string,
    TStatesKeys extends string
>(
    settings: string | ISettings<TModsKeys, TStatesKeys>,
    enabled: Partial<Record<TModsKeys | TStatesKeys, boolean>> = {},
    maps: Partial<Record<TModsKeys | TStatesKeys, string>> = {}
): string {
    //function doesn't return anything yet
    return '';
}

gen({
    mods: ['one', 'two', 'three'],
    states: ['disabled', 'fixed']
}, {
    one: true,
    disabled: true,
}, {
    one: 'first',
    two: 'second',
    fixed: 'static',
});

推荐阅读