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_Generics_Union Types - Fatal编程技术网

Typescript 基于泛型的类字段的类型

Typescript 基于泛型的类字段的类型,typescript,generics,union-types,Typescript,Generics,Union Types,想象一下下面的代码(): 类型AvailableType={ “数组”:数组 更新 (更新至) 应该可以根据类型属性键入检查值: //在包装类中,应该可以使用,因为只有当类型为“array”时,值才能是数组: 公共值(val:未知){ if(this.type=='array'){ 这个.value.push(val); } } 基本问题是,泛型类型参数没有通过控制流分析缩小范围,这在TypeScript中是一个相当长期的开放问题,有关更多信息,请参阅 当您在开关/大小写语句中选中类型时

想象一下下面的代码():

类型AvailableType={
“数组”:数组
  • 更新 (更新至) 应该可以根据
    类型
    属性键入检查

    //在包装类中,应该可以使用,因为只有当类型为“array”时,值才能是数组:
    公共值(val:未知){
    if(this.type=='array'){
    这个.value.push(val);
    }
    }
    

    基本问题是,泛型类型参数没有通过控制流分析缩小范围,这在TypeScript中是一个相当长期的开放问题,有关更多信息,请参阅

    当您在
    开关
    /
    大小写
    语句中选中
    类型
    时,编译器可以将
    类型
    变量的类型缩小为文本类型
    数组
    ,但它不会将类型参数
    T
    缩小为
    数组
    。因此,编译器无法验证是否可以安全地分配
    任何变量[]
    类型
    可用类型[T]
    的值。编译器必须执行一些当前没有执行的分析,例如“好的,如果
    类型==”数组“
    ,我们从
    类型
    推断
    T
    ,然后在这个
    案例
    块中,我们可以将
    T
    缩小到
    ”数组“
    ,因此
    this.value
    的类型是
    AvailableTypes[“array”]
    ,也就是说,
    any[]
    ,因此将
    []
    分配给它是安全的。”但这不会发生

    同样的问题也会导致“
    未明确分配”错误。编译器没有必要的资金来查看
    开关
    /
    案例
    是否用尽了
    t
    的所有可能性,因为它在这里不进行控制流分析


    这里最简单的解决方法是告诉编译器您知道自己在做什么,因为它无法验证

    要处理穷尽性问题,您可以创建一个抛出的
    缺省值
    案例,如下所示:

    class Wrapper<T extends keyof AvailableTypes> {
    
        private readonly type: T;
        private readonly value: AvailableTypes[T];
        constructor(type: T) {
            this.type = type;
    
            switch (type) {
                case 'array':
                    this.value = [] as AvailableTypes[T]; // assert
                    break;
                case 'string':
                    this.value = '' as AvailableTypes[T]; // assert
                    break;
                case 'object':
                    this.value = {} as AvailableTypes[T]; // assert
                    break;
                default:
                    throw new Error("HOW DID THIS HAPPEN"); // exhaustive
            }
        }
    }
    

    另一个解决方法()是利用这样一个事实:如果您有一个
    t
    类型的值
    t
    ,并且一个
    k类型的键
    k
    扩展了t
    的键,那么
    t[k]
    的类型将被编译器视为
    t[k]
    。因此,如果我们可以创建一个有效的
    AvailableType
    ,我们可以使用
    类型
    对其进行索引。可能如下所示:

    class Wrapper<T extends keyof AvailableTypes> {
        private readonly type: T
        private readonly value: AvailableTypes[T];
        constructor(type: T) {
            this.type = type;
            const initValues: AvailableTypes = {
                array: [],
                string: "",
                object: {}
            };
            this.value = initValues[type];
        }
    }
    
    类包装器{
    私有只读类型:T
    私有只读值:AvailableType[T];
    建造师(类型:T){
    this.type=type;
    常量初始值:AvailableType={
    阵列:[],
    字符串:“”,
    对象:{}
    };
    this.value=initValues[type];
    }
    }
    
    这是一种比类型断言和
    switch
    语句更好的方法,而且启动时是相当类型安全的


    好的,希望其中一个能帮上忙。祝你好运



    更新:

    谢谢你的详细回答!但是当我试图检查
    类型
    是否为
    数组
    ,并尝试将某些内容推入值时,它失败了:(即使
    type
    基本上严格地绑定到value属性……我在问题中看不到这一点;我错过了吗?或者这是一个单独的问题还是后续问题?a总是很有帮助。祝你好运!对不起,我已经更新了问题-
    type
    属性实际上是用于此目的的!问题是一样的,我看到的唯一没有完全重构的解决方案是类型断言:
    (this.value as AvailableTypes[“array”]).push(val);
    。如果我知道您计划在
    包装器的实现中进行这样的操作,我建议您使用一个有区别的联合,而不是使用类或使用一系列子类(联合的每个成员有一个子类).我在答案的底部添加了一个游乐场链接,显示了与兄弟班的歧视性结合可能比单一普通班更有效。祝你好运!
    
    class Wrapper<T extends keyof AvailableTypes> {
        private readonly type: T
        private readonly value: AvailableTypes[T];
        constructor(type: T) {
            this.type = type;
            const initValues: AvailableTypes = {
                array: [],
                string: "",
                object: {}
            };
            this.value = initValues[type];
        }
    }