#typescript #type-inference
#typescript #вывод типа
Вопрос:
У меня есть класс DataHolder для управления информацией о точках и линиях. У DataHolder есть 2 дочерних класса. Каждый дочерний класс управляет одним типом данных (число, number[])
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;
Далее, у меня есть перегруженные функции для получения и заполнения де-данных:
const holders = new Map<DataType, holders>();
const currentTypes: DataType[] = [];
function getDataHolder(type: DataType.POINT): PointHolder;
function getDataHolder(type: DataType.LINE): LineHolder;
function getDataHolder(type: DataType): holders {
if (!holders.has(type)) {
holders.set(type, DataHolder.factory(type));
currentTypes.push(type);
}
return holders.get(type);
}
function add(type: DataType.POINT, ids: number): void;
function add(type: DataType.LINE, ids: number[]): void;
function add(type: DataType, ids: number | number[]): void {
let hldr: holders;
switch (type) {
case DataType.POINT:
hldr = getDataHolder(type);
hldr.add(ids); // Argument of type 'number | number[]' is not assignable to parameter of type 'number'.
break;
case DataType.LINE: {
hldr = getDataHolder(type);
hldr.add(ids); // Argument of type 'number | number[]' is not assignable to parameter of type 'number[]'.
break;
}
default:
break;
}
}
function clear() {
for (const type of currentTypes) {
const hldr = getDataHolder(type); // No overload matches this call
hldr.clear();
}
}
Каков правильный способ определения перегруженных функций «getDataHolder» и «add» для вывода правильных типов передаваемых аргументов.
Ответ №1:
typescript имеет некоторое странное поведение, когда дело доходит до типов объединения
добавить функцию: typescript не может вывести тип на основе другого аргумента. но он может выводить свойства объекта, чтобы вы могли записать его как
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;
}
}
очистить функцию: это тоже довольно странная функция, которую знает typescript 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);
}