推断工厂类别

问题描述

我有一个DataHolder类来管理点和线信息。 DataHolder有2个子类。每个子类都管理一种类型的数据(数字,数字[])

{
  "rules": {
    "user_data": {
      "$uid": {
        "transdet":{
            ".read": "auth != null && auth.uid == $uid"
            ".write": "false"
       }
        "avatar":{
            ".read": "auth != null && auth.uid == $uid"
            ".write": "auth != null && auth.uid == $uid"
       }
      }
    }
  }
}

接下来,我有一个重载的函数获取和填充de dataHolders:

const enum DataType { POINT,LINE }

class DataHolder<T> {
    protected type: DataType;
    protected data: T[] = [];

    constructor(type: DataType) { this.type = type; }

    public add(data: T) { this.data.push(data); }

    public clear() { this.data.length = 0; }

    public static factory(type: DataType) {
        switch (type) {
            case DataType.POINT: return new PointHolder();
            case DataType.LINE: return new LineHolder();
            default: return undefined;
        }
    }
}
class PointHolder extends DataHolder<number> {
    constructor() { super(DataType.POINT); }
}
class LineHolder extends DataHolder<number[]> {
    constructor() { super(DataType.LINE); }
}
type holders = PointHolder | LineHolder;

定义重载函数“ getDataHolder”和“ add”以推断传递的参数的正确类型的正确方法是什么。

解决方法

打字稿在联合类型方面有一些奇怪的行为

添加功能: 打字稿无法基于其他参数推断类型。但是它可以推断对象的属性,因此您可以将其写为

interface pointParams {
    type: DataType.POINT; ids: number;
}

interface lineParams {
    type: DataType.LINE; ids: number[];
}

type addFunc = (para: pointParams | lineParams) => void

let add:addFunc = function(para) {
    let hldr: holders;
    switch (para.type) {
        case DataType.POINT:
            hldr = getDataHolder(para.type);
            hldr.add(para.ids);      // Argument of type 'number | number[]' is not assignable to parameter of type 'number'.
            break;
        case DataType.LINE: {
            hldr = getDataHolder(para.type);
            hldr.add(para.ids);      // Argument of type 'number | number[]' is not assignable to parameter of type 'number[]'.
            break;
        }
        default:
            break;
    }
}

清除函数:这也是一种奇怪的打字稿,知道DataType == DataType.POINT | DataType.LINE,但它不知道DataType.POINT | DataType.LINE == DataType,因此您必须声明getDataHolder使其起作用

function getDataHolder(type: DataType.POINT): PointHolder;
function getDataHolder(type: DataType.LINE): LineHolder;
function getDataHolder(type: DataType): holders;
function getDataHolder(type: DataType): holders {
    if (!holders.has(type)) {
        holders.set(type,DataHolder.factory(type));
        currentTypes.push(type);
    }
    return holders.get(type);
}