Строгая проверка псевдонимов машинописного текста

Есть ли способ применить машинописный текст к еще более строгой проверке типов, вплоть до проверки псевдонимов?

Чего я хочу добиться, так это определить типы, такие как:

type kilograms = number;
type kilometers = number;
type kilogramsPerKilometer = number;

И чтобы быть уверенным, что я не помещаю неправильно введенное значение в переменную, например:

let x: kilograms = 123;
let y: kilometers = 256;
let z: kilogramsPerKilometer = x / y; // Will popup an error here saying that types are incompatible

В этом случае потребуется явное приведение типа:

let x: kilograms = 123;
let y: kilometers = 256;
let z: kilogramsPerKilometer = <number>x / <number>y; // Will downcast `kilograms` and `kilometers` types to `number` and then up-cast types to `kilogramsPerKilometer`

person Lu4    schedule 22.01.2017    source источник


Ответы (3)


В TS нет номинальной типизации (пока) https://github.com/Microsoft/TypeScript/issues/202

Это принятое решение (с использованием различающих союзов):

interface kilograms {
  kind: "kilograms";
  value: number;
}

interface kilometers {
  kind: "kilometers";
  value: number;
}

function kilosPerKiloms(x: kilograms, y: kilometers): kilogramsPerKilometer {
  return x.value / y.value;
}

const x = { kind: "kilograms", value: 123 };
const y = { kind: "kilometers", value: 256 };
const z = kilosPerKiloms(x, y);
// const z = kilosPerKiloms(y, x); // => error

Больше информации там:

https://www.typescriptlang.org/docs/handbook/advanced-types.html

https://basarat.gitbooks.io/typescript/content/docs/types/distributed-unions.html

person Benoit B.    schedule 10.05.2017

Вы ищете именную типизацию. Поддержка планируется для будущих версий TypeScript (см. дорожную карту). На данный момент вы должны использовать это: https://basarat.gitbooks.io/typescript/docs/tips/nominalTyping.html

person nikeee    schedule 24.07.2017
comment
Спасибо за то, что дали ему имя! Я искал именно это. - person guillemus; 17.01.2021
comment
@guillemus Для получения дополнительных реализаций вы также можете искать фирменные типы. - person nikeee; 18.01.2021

Каким-то образом я потерял этот вопрос, на самом деле выясняя интересное решение. Это красивее, не влияет на интерфейс и не загрязняет список предложений IDE.

export type Nominal<T> = T & { readonly '': unique symbol };

export type Miles = Nominal<number>;
export type Kilograms = Nominal<number>;
export type MilesPerKilogram = Nominal<number>;

var a: Miles = 3; // error
var b: Kilograms = 3; // error
var c: MilesPerKilogram = x / y; // error

var x: Miles = 3 as Miles; // ok
var y: Kilograms = 3 as Kilograms; // ok
var u: MilesPerKilogram = x / y as MilesPerKilogram; // ok

Работает на любых типах

person Lu4    schedule 30.06.2021
comment
Интересный трюк, спасибо за его предоставление! :) - person M'λ'; 06.07.2021