TypeScript Duck Typing, нужна сильная статическая печать

TypeScript использует время компиляции (статическое) утиный ввод.

Я фанат расширения примитивных типов для предотвращения неправильной подстановки. Например, мне нравится давать переменной номера кредитной карты тип номера кредитной карты, а не целое число. Недавно я попытался сделать это в TypeScript с парой интерфейсов, расширяющих String, и обнаружил, что они свободно заменяют друг друга (и эта строка заменяет оба).

Я действительно хотел бы получить номинальную типизацию во время компиляции. Любые идеи?


person Eric    schedule 26.03.2014    source источник
comment
Вы имеете в виду номинальный набор текста? Система типов TypeScript является статической, а семантика времени выполнения JavaScript в основном слабая, что может конфликтовать с сильной системой типов.   -  person Ryan Cavanaugh    schedule 27.03.2014
comment
Да, номинальный набор текста - это то, что мне было нужно. Отредактированная ссылка на строгую типизацию выше. Спасибо!   -  person Eric    schedule 27.03.2014
comment
comment
Ответ Лодевийка Богарда в этом (более молодом) возможном дубликате дает отличное объяснение того же решения, которое я предложил ниже. Куба Джагода также предлагает один, демонстрирующий, что частные члены могут использоваться без риска совпадения имен их членов.   -  person Eric    schedule 30.06.2016


Ответы (2)


Я придумал один способ научиться печатать сильнее. Мне это не очень нравится. К каждому типу добавляется специальное поле или метод, что делает его несовместимым с другими, которые можно было бы принять за уток.

Следующее не позволяет заменять Parrot на Duck, потому что у класса Duck есть дополнительный метод (поэтому Parrot не может набрать утку). Воробьи и попугаи, по-видимому, можно заменить при наборе утиных текстов, потому что попугай не может делать ничего такого, что не может воробей, и наоборот. Конечно, Утка может заменить Попугая, потому что если это звучит как попугай, то это попугай.

Протестируйте с помощью www.typescriptlang.org/Playground/:

class Sparrow {
    sound = "cheep";
}
class Parrot {
    sound = "squawk";
}
class Duck {
    sound = "quack";
    swim(){
        alert("Going for a dip!");
    }
}
var parrot: Parrot = new Sparrow(); // substitutes
var sparrow: Sparrow = new Parrot(); // substitutes
var parrotTwo: Parrot = new Duck();
var duck: Duck = new Parrot(); // IDE & compiler error

alert("Parrot says "+parrot.sound+" and sparrow says "+sparrow.sound+", and 2nd parrot says "+parrotTwo.sound);
alert("A duck says "+duck.sound);

Практически я бы сделал это (что работает в моей среде IDE, но не на игровой площадке):

interface RawUri extends String {
    rawUri;
}

interface EncodedUri extends String {
    encodedUri;
}

var e: EncodedUri = new RawUri(); // IDE & compiler error
var r: RawUri = new EncodedUri(); // IDE & compiler error

Неприятно и возможность для другого интерфейса случайно использовать то же имя поля. Я полагаю, что можно было бы добавить случайный элемент к члену против утки.

person Eric    schedule 26.03.2014

Пожалуйста, рассмотрите следующий вопрос:

Распознавание атомарных типов (номинальные атомные типы) в TypeScript

На этом примере:

export type Kilos<T> = T & { readonly discriminator: unique symbol };
export type Pounds<T> = T & { readonly discriminator: unique symbol };

export interface MetricWeight {
    value: Kilos<number>
}

export interface ImperialWeight {
    value: Pounds<number>
}

const wm: MetricWeight = { value: 0 as Kilos<number> }
const wi: ImperialWeight = { value: 0 as Pounds<number> }

wm.value = wi.value;                  // Gives compiler error
wi.value = wi.value * 2;              // Gives compiler error
wm.value = wi.value * 2;              // Gives compiler error
const we: MetricWeight = { value: 0 } // Gives compiler error
person Lu4    schedule 23.05.2019