代码之家  ›  专栏  ›  技术社区  ›  Bart van den Burg

typescript:基于属性值的类型确定

  •  0
  • Bart van den Burg  · 技术社区  · 8 年前

    我非常确定typescript能够基于属性值确定扩展类,例如:

    interface Base {
        type: string;
        child?: Base;
    }
    
    interface Ext extends Base {
        type: 'test';
        sth: string;
    }
    
    z({
        type: 'a',
        child: {
            type: 'b',
        }
    }); // ok
    
    z({
        type: 'a',
        child: {
            type: 'test',
            sth: 'val'
        }
    }); // not ok
    
    function z(input: Base) { }
    

    上面的例子不起作用,ts告诉我属性 sth 界面上不存在 Base .我需要改变什么才能让TS理解孩子实际上是 Ext ,因为 'test' type 财产?

    3 回复  |  直到 8 年前
        1
  •  1
  •   Naftali    8 年前

    您需要将其声明为类型 Ext 应该会过去的

    let x: Ext = {
        type: 'test',
        sth: 'value'
    }
    
        2
  •  0
  •   artem    8 年前

    这个错误来自 excess property check ,仅当使用对象文本初始化变量时才执行此操作。为了避免这种情况,您需要使用非对象文本的内容初始化该值,例如,您可以添加中间变量

    let o = {
        type: 'test',
        sth: 'value'
    }
    let x1: Base = o;
    

    或者可以添加类型断言

    let x2: Base = {
        type: 'test',
        sth: 'value'
    } as Base;
    

    另一个解决办法是 Base z 泛型,参数化类型为 Child 它应该是 底座 (请注意,自引用类型约束很难纠正,但在这种情况下似乎很有效,次要的问题是 底座 导致 底座 在约束中推断为 Child extends Base<{ type: string; child?: Base<any> | undefined; } - any 这里可能有问题,但似乎不会影响示例中的任何内容)。

    interface Base<Child extends Base = { type: string, child?: Base }> {
        type: string;
        child?: Child;
    }
    
    interface Ext extends Base {
        type: 'test';
        sth: string;
    }
    
    z({
        type: 'a',
        child: {
            type: 'b',
        }
    }); // ok
    
    z({
        type: 'a',
        child: {
            type: 'test',
            sth: 'val'
        }
    }); // not ok
    
    function z<B extends Base>(input: B) { }
    
        3
  •  0
  •   Bart van den Burg    8 年前

    我想我明白了:

    interface Base {
        child?: Ext;
    }
    
    interface Ext1 extends Base {
        type: 'a';
    }
    interface Ext2 extends Base {
        type: 'test';
        sth: string;
    }
    
    type Ext = Ext1 | Ext2;
    
    z({
        type: 'a',
        child: {
            type: 'test',
            sth: 'x'
        }
    });
    
    function z(input: Ext) { }
    

    如果 sth 未定义while type 'test' 而不是相反

    推荐文章