字符串或数字字典类型参数

时间:2016-06-09 09:36:48

标签: typescript

我有这个功能:

interface NumDict<T> {
  [key : number] : T
}

export function mapNumDictValues<T,R>(dict: NumDict<T>, f: (v: T, key?: number) => R): NumDict<R> {
  let emptyDict : NumDict<R> = {};
  return Object.keys(dict).reduce((acc, key) => {
    const keyInt = parseInt(key);
    acc[keyInt] = f(dict[keyInt], keyInt);
    return acc;
  }, emptyDict);
}

现在我希望它适用于字符串索引字典以及数字索引字典,例如类似的东西:

function mapDictValues<K extends string|number,T,R>(obj: {[id: K]: T}, f: (v: T, key?: K) => R): {[id: K]: R} {

但是,这会让我犯这个错误:

error TS1023: An index signature parameter type must be 'string' or 'number'.

有办法吗?

2 个答案:

答案 0 :(得分:2)

你所追求的是不容易完成的(至少我找不到办法)因为javascript如何处理对象键(仅限字符串)和对索引表达式的字符串限制(字符串/数字/符号/任何)以及类型number | stringnumber / string之间的差异。

你设法获得的唯一类型安全(据我所知)是你在一个案例中使用noImplicitAny(模糊错误)得到错误,但你仍然受限于你可以用这个做什么字典。

我对你的情况了解不多,但听起来你没有什么可以获得合适的解决方案,除非你真的需要这种类型安全然后我觉得它更好只需将您的密钥视为字符串并将其解决,但如果您确实需要它,那么我建议您创建自己的字典类型实现来处理事情,例如:

interface Dict<K extends number | string, V> {
    get(key: K): V;
    set(key: K, value: V): void;
    mapValues<R>(f: (v: V, key?: K) => R): Dict<K, R>;
}

abstract class BaseDict<K extends number | string, V> implements Dict<K, V> {
    protected items: { [key: string]: V } = Object.create(null);

    get(key: K): V {
        return this.items[key.toString()];
    }

    set(key: K, value: V): void {
        this.items[key.toString()] = value;
    }

    abstract keys(): K[];

    values(): V[] {
        return Object.keys(this.items).map(key => this.items[key]);
        // or Object.values(this.items) with ES6
    }

    mapValues<R>(fn: (v: V, key?: K) => R): Dict<K, R> {
        let dict: Dict<K, R> = Object.create(this.constructor.prototype);
        this.keys().forEach(key => dict.set(key, fn(this.get(key), key)));
        return dict;
    }
}

class NumDict<V> extends BaseDict<number, V> {
    keys(): number[] {
        return Object.keys(this.items).map(key => parseFloat(key));
    }
}

class StringDict<V> extends BaseDict<string, V> {
    keys(): string[] {
        return Object.keys(this.items);
    }
}

你需要使用ctors创建你的dicts,这不像使用{}那样舒服,但是你确实可以控制事物,例如注意调用map函数时({ {1}} {}} {}} {}} {}} {}} {}} {}} {}} {}} {}} {}} {}} {}}

答案 1 :(得分:2)

尝试一下:

interface IStringToNumberDictionary {
    [index: string]: number;
}


interface INumberToStringDictionary {
    [index: number]: string;
}

type IDictionary = IStringToNumberDictionary | INumberToStringDictionary;

示例:

let dict: IDictionary = Object.assign({ 0: 'first' }, { 'first': 0 });
let numberValue = dict["first"]; // 0
let stringValue = dict[0]; // first

您的情况如下:

interface IStringKeyDictionary<T> {
    [index: string]: T;
}


interface INumberKeyDictionary<T> {
    [index: number]: T;
}

type IDictionary<T> = IStringKeyDictionary<T> | INumberKeyDictionary<T>;