Комментарии 13
>В данной статья я расскажу о том, как решить эту проблему средствами TSLint
Причем тут tslint?
Причем тут tslint?
Вот только при таком подходе у идентификаторов появляется какое-то левое поле _type. Лучше использовать символ:
const flavorType = Symbol("flavorType");
export type Flavor<T, FlavorT> = T & { [flavorType]?: FlavorT };
По-хорошему, ещё и строки "CarId" с "BoatId" нужно за символами спрятать, но TS пока что так не умеет.
Да, вместо _type можно использовать как _myProjectNameType, так и Symbol, если есть опасения из-за возможного конфликта имен. Главное, что после компиляции из TypeScript в JavaScript эта информация о типах будет удалена.
Кстати, сами разрабочики TypeScript в своих исходниках используют брендинг. Поэтому использование левого поля _type можно считать допустимым.
Интересное решение, но непонятно, насколько оно стабильное. Может оказаться, что в будущих версиях Typescript станет умнее, и будет игнорировать поле `_type` потому что оно опциональное и нигде не используется. Тогда CarId и BoatId внезапно станут одинаковым типом.
Хотелось бы узнать, кто что думает об этом аспекте.
Хотелось бы узнать, кто что думает об этом аспекте.
>> Эмулируем самую строгую типизацию
Здесь опечатка: type BoatId = number & { _type: 'BookId'};
Все мы поняли что там должно быть BoatId. Но это тот самый случай, когда могут 2 разных типа проскочить по одному имени :(
Кстати, как-то копался на github и newtype-ts
Здесь опечатка: type BoatId = number & { _type: 'BookId'};
Все мы поняли что там должно быть BoatId. Но это тот самый случай, когда могут 2 разных типа проскочить по одному имени :(
Кстати, как-то копался на github и newtype-ts
Можно ещё так:
declare const CarSymbol: unique symbol;
type CarId = string & typeof CarSymbol;
declare const BoatSymbol: unique symbol;
type BoatId = string & typeof BoatSymbol;
function processCar(id: CarId) {}
function processBoat(id: BoatId) {}
function processString(value: string) {}
let carId = <CarId>'car uuid';
let boatId = <BoatId>'boat uuid';
processCar(carId);
processCar(boatId); // error
processBoat(carId); // error
processBoat(boatId);
processString(carId); // ok
processString(boatId); // ok
Вообще горячий топик
https://github.com/Microsoft/TypeScript/issues/202
Самая удобная реализация, что я смог придумать, есть в $mol_data_nominal.
const Weight = $mol_data_nominal({ Weight : $mol_data_integer })
const Length = $mol_data_nominal({ Length : $mol_data_integer })
let len = Length(10)
len = Length(20) // Validate
len = 20 as typeof Length.Value // Cast
len = 20 // Compile time error
len = Weight(20) // Compile time error
len = Length( 20.1 ) // Run time error
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Номинативная типизация в TypeScript или как защитить свой интерфейс от чужих идентификаторов