【问题标题】:When does TypeScript use structural typing?TypeScript 什么时候使用结构类型?
【发布时间】:2020-03-05 21:54:14
【问题描述】:

鉴于下面的类型,为什么编译器允许下面的赋值?我猜它与在某些情况下使用结构类型的 TypeScript 有关(即因为 SuccessFailure 在结构上是等效的,编译器将它们视为可互换的),但我想我不清楚在什么条件下是结构的打字使用。

////////////////////
// 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 的解决方案是为类型赋予不同的字段(即svaluefvalue)。这可行,但我更喜欢界面相同,所以我选择了下面的解决方案,使用符号来区分类(如果这有与之相关的问题,请加入):

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);
    }
}

【问题讨论】:

    标签: typescript type-inference structural-typing


    【解决方案1】:

    哇。这是非常微妙的,但试试这个:

    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&lt;S, F&gt; 是任何具有value 类型为S | F 的属性。因此,Result&lt;S, F&gt; 可分配给 Result&lt;F, S&gt; — type-union 是可交换的。

    在我的版本中,Result&lt;S, F&gt; 是具有svalue 类型为S 的属性或fvalue 类型为F 的属性,因此Result&lt;S, F&gt; 不能分配给Result&lt;F, S&gt;

    【讨论】:

    • 类型联合可交换性让我失望。感谢您指出。回想起来,这完全有道理,但再多的盯着代码也不会让我到达那里。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 2010-09-10
    • 2018-05-05
    • 2010-12-08
    • 2015-03-05
    相关资源
    最近更新 更多