TypeScript 什么时候使用结构类型?
When does TypeScript use structural typing?
给定以下类型,为什么编译器允许以下赋值?我猜这与在某些情况下使用结构类型的 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);
好奇的额外背景:
正如 Malvolio 指出的那样,问题在于类型联合是可交换的,而解决这个问题的方法是让类型在结构上不等价。 Malavolio 的解决方案是为类型提供不同的字段(即 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);
}
}
哇。这是非常微妙的,但试试这个:
class Success<S> {
constructor(public svalue: S) { }
static create<S, F>(value: S):Result<S, F> {
return new Success<S>(value);
}
}
class Failure<F> {
constructor(public fvalue: F) {}
static create<S, F>(value: F): Result<S, F> {
return new Failure<F>(value);
}
}
type Result<S, F> = Success<S> | Failure<F>;
const f: Result<number, Error> = Failure.create(2);
根据定义,您的 Result<S, F>
是具有类型 S | F
的 属性 value
的任何内容。因此,Result<S, F>
可分配给 Result<F, S>
— 类型联合是可交换的。
在我的版本中,Result<S, F>
是类型为 S
的 属性 svalue
或 属性 fvalue
使用类型 F
,因此 Result<S, F>
不可分配给 Result<F, S>
给定以下类型,为什么编译器允许以下赋值?我猜这与在某些情况下使用结构类型的 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);
好奇的额外背景:
正如 Malvolio 指出的那样,问题在于类型联合是可交换的,而解决这个问题的方法是让类型在结构上不等价。 Malavolio 的解决方案是为类型提供不同的字段(即 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);
}
}
哇。这是非常微妙的,但试试这个:
class Success<S> {
constructor(public svalue: S) { }
static create<S, F>(value: S):Result<S, F> {
return new Success<S>(value);
}
}
class Failure<F> {
constructor(public fvalue: F) {}
static create<S, F>(value: F): Result<S, F> {
return new Failure<F>(value);
}
}
type Result<S, F> = Success<S> | Failure<F>;
const f: Result<number, Error> = Failure.create(2);
根据定义,您的 Result<S, F>
是具有类型 S | F
的 属性 value
的任何内容。因此,Result<S, F>
可分配给 Result<F, S>
— 类型联合是可交换的。
在我的版本中,Result<S, F>
是类型为 S
的 属性 svalue
或 属性 fvalue
使用类型 F
,因此 Result<S, F>
不可分配给 Result<F, S>