Учитывая приведенные ниже типы, почему компилятор разрешает присваивание ниже? Я предполагаю, что это связано с TypeScript, использующим структурную типизацию в некоторых ситуациях (то есть, поскольку Success
и Failure
структурно эквивалентны, компилятор рассматривает их как взаимозаменяемые), но я предполагаю, что мне не ясно, при каких условиях структурнаяпечатать использовал.
////////////////////
// Types
////////////////////
class Success<S> {
constructor(public value: S) { }
static create<S, F>(value: S):Result<S, F> {
return new Success<S>(value);
}
}
class Failure<F> {
constructor(public value: F) {}
static create<S, F>(value: F): Result<S, F> {
return new Failure<F>(value);
}
}
type Result<S, F> = Success<S> | Failure<F>;
////////////////////
// Usage
////////////////////
/*
How is the assignment below allowed by the compiler?
Failure.create produces a Result<unknown, number> which should not
be assignable to a Result<number, Error>
*/
const f: Result<number, Error> = Failure.create(2);
ДОПОЛНИТЕЛЬНЫЙ КОНТЕКСТ ДЛЯ ЛЮБИМОГО: Как указывает Мальволио, проблема заключается в том, что объединения типов являются коммутативными, а способ обхода состоит в том, чтобы типы не были структурно эквивалентными. Решение Малаволио состоит в том, чтобы дать типам различные поля (например, svalue
и fvalue
). Это работает, но я предпочитаю, чтобы интерфейс был таким же, поэтому я выбрал решение ниже, используя символы, чтобы различать классы (Если это связано с проблемами, пожалуйста, включите):
export const SuccessType = Symbol();
export class Success<S> {
public readonly resultType = SuccessType;
private constructor(public value: S) {}
static create<S, F>(value: S): Result<S, F> {
return new Success<S>(value);
}
}
export const FailureType = Symbol();
export class Failure<F> {
public readonly resultType = FailureType;
private constructor(public value: F) {}
static create<S, F>(value: F): Result<S, F> {
return new Failure<F>(value);
}
}