Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript:基于属性值的类型确定_Typescript - Fatal编程技术网

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

Typescript:基于属性值的类型确定,typescript,Typescript,我非常确定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', chil

我非常确定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
上不存在。由于
type
属性上的值
'test'
,我需要更改什么,以便TS理解子项实际上是
Ext
的类型?

您需要将其声明为type
Ext
,并且应该通过

let x: Ext = {
    type: 'test',
    sth: 'value'
}
此错误来自,仅当使用对象文字初始化变量时才会发生。为了避免这种情况,您需要使用非对象文字的内容初始化值,例如,您可以添加中间变量

let o = {
    type: 'test',
    sth: 'value'
}
let x1: Base = o;
也可以添加类型断言

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

另一种解决方案是使
Base
z
通用,在
Child
类型上参数化,该类型应为
Base
的子类型(请注意,自引用类型约束很难获得正确的结果,但在这种情况下似乎有效,次要问题是
Base
的默认值导致约束中的
Base
被推断为
Child extends Base,我想我已经解决了:

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
,而
type
'test'
,而不是反过来定义
sth
,则此示例将失败

不应该能够确定它必须已经是
Ext
,因为
Ext
扩展了
Base
,但基于
type
的值进行了明确的区分xt仍然是Base(因此可以工作),但它包含的键在Base接口中不存在。两者都可以工作,但我非常确定我曾经看到过一个例子,说明TS如何自己解决这个问题。
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) { }