Предположим, у меня есть два типа A
и B
в TypeScript, и я не хочу, чтобы значения типа A
можно было присвоить B
.
I хотел бы принудительно применить это, так что если один (или оба) из типов случайно изменятся, чтобы разрешить назначение, мы получим ошибку компиляции или сбой теста. Есть ли способ выполнить sh это в TypeScript?
Конечно, легко добиться того, чтобы присваивание было законным, просто выполнив присваивание в тесте. Но я не могу сразу увидеть способ обеспечить, чтобы конкретный фрагмент кода не проходил проверку типа TypeScript.
Вот еще кое-что о том, почему я хочу это сделать. Я хочу обеспечить неизменность определенного типа, примерно так:
interface MyImmutableThing {
readonly myfield: string;
}
Однако эта проблема делает эту проблему c, потому что если у меня есть идентичный в остальном изменяемый тип например:
interface MyThing {
myfield: string;
}
, тогда значения типа MyImmutableThing
могут быть присвоены MyThing
, что позволяет обойти безопасность типов и изменить myfield
. Следующий код компилируется, запускается и вызывает изменение imm.myfield
:
const imm: MyImmutableThing = {myfield: 'mumble'};
const mut: MyThing = imm;
mut.myfield = 'something else';
Я не знаю способа надежно обеспечить неизменность такого типа во время компиляции, но я могу по крайней мере реализовать принудительное исполнение во время выполнения с использованием вместо этого класса, например:
class MyImmutableThing {
private _myfield: string;
get myfield(): string { return this._myfield; }
constructor(f: string) { this._myfield = f; }
}
Тогда, хотя код, подобный приведенному ниже, все равно будет компилироваться, это приведет к ошибке времени выполнения: затем напишите тест, который утверждает, что возникает эта ошибка времени выполнения.
Однако, если мое поле имеет тип массива (или кортежа), ситуация меняется:
interface MyArrayThing {
myfield: string[];
}
interface MyImmutableArrayThing {
readonly myfield: readonly string[];
}
Теперь значение MyImmutableArrayThing
не присваивается MyArrayThing
из-за readonly
типа массива. Следующее не будет компилироваться:
const imm: MyImmutableArrayThing = {myfield: ['thing']};
const mut: MyArrayThing = imm;
Это хорошо, поскольку дает нам больше уверенности в неизменности во время компиляции, чем мы получили с полем string
. Однако теперь сложнее написать тесты, которые фиксируют наше намерение здесь, или иным образом обеспечить его выполнение.
Невозможность присваивания MyImmutableArrayThing
s на MyArrayThing
является ключом к системе типов, обеспечивающей требуемые свойства. , но как нам помешать кому-либо внести какие-либо изменения, например добавить readonly
к массиву в MyArrayThing
, разрешить что-то подобное и нарушить требуемое свойство? на данный момент довольно сбивает с толку, поэтому возможность делать утверждения такого рода была бы весьма полезна для предотвращения регрессов.
Вот ссылка на TypeScript Playground для кода в этом вопросе.