Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/396.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

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
Javascript 如何在typescript中定义动态泛型约束_Javascript_Typescript_Typescript Generics - Fatal编程技术网

Javascript 如何在typescript中定义动态泛型约束

Javascript 如何在typescript中定义动态泛型约束,javascript,typescript,typescript-generics,Javascript,Typescript,Typescript Generics,我有一个抽象基类,它有一个泛型类型参数,如下所示: 抽象类基类{ 构造函数(受保护的值:T){} } 我从基继承多个类。例如: class-TBase扩展了基{ 构造函数(值:number){ 超级(价值); } } 类XBase扩展了基{ 构造函数(值:字符串){ 超级(价值); } } 现在,我想编写一个工厂函数,根据输入属性返回一个新的基: type ValidTypes='string'|'integer'|'decimal'|'boolean'|'datetime'; 类型vali

我有一个抽象基类,它有一个泛型类型参数,如下所示:

抽象类基类{
构造函数(受保护的值:T){}
}
我从基继承多个类。例如:

class-TBase扩展了基{
构造函数(值:number){
超级(价值);
}
}
类XBase扩展了基{
构造函数(值:字符串){
超级(价值);
}
}
现在,我想编写一个工厂函数,根据输入属性返回一个新的基:

type ValidTypes='string'|'integer'|'decimal'|'boolean'|'datetime';
类型validFor=T扩展“字符串”|“日期时间”
? 一串
:T扩展“整数”|“小数”
? 数
:T扩展“布尔”
? 布尔值
:从不;
函数getBase(类型:T,值:P):Base

{ 开关(类型){ 案例“编号”:新的TBase(强制枚举器(值));中断; ... } }

将“string”作为第一个参数传递时,第二个参数只能是string类型。对于“decimal”,类型P只能是一个数字

但我有两个问题。像这样调用函数时:

getBase('string','5');
它起作用了,但上面说签名是

function getBase<'string', '5'>(type: 'string', value: '5'): Base<'5'>
函数getBase(类型:'string',值:'5'):Base 它不明白为什么它不是解析为字符串,而是解析为value的值

另一个问题是,当我返回一个新的TBase()时,它表示它也可以是字符串或布尔值:

'number'可分配给'p'类型的约束,但'p'可以用约束'string | number | boolean'的不同子类型实例化

我找了很多关于这个的东西,但还是绕不过去。有人能解释一下为什么会这样吗?即使我显式地将其强制转换为Base,它也会抛出错误(返回new TBase()作为Base)

我尝试的另一种方法是使用函数重载,但这看起来有点奇怪,而且不正确:

getBase(类型:'decimal'|'integer',值:number):Base
getBase(类型:“string”|“datetime”,值:string):Base
getBase(类型:'boolean',值:boolean):Base
getBase(类型:ValidTypes,值:number | boolean | string):Base{
...
}
我想这样说:


getBase('string','thisMustBeAString');//=>基础
getBase('decimal',54/*必须是数字*/)/=>Base;
我错过了什么?我很长一段时间都在默默地挣扎着。。提前谢谢

编辑:


我非常努力地让您的第一种方法在没有强制转换的情况下以完全类型安全的方式工作,但失败了

还处理类型依赖于参数类型的返回类型,一些答案建议使用重载。正如您已经发现的,这是解决问题的一种方法——尽管实现的返回类型不应该是
Base
,而是
Base | Base | Base

如果您可以稍微更改一下调用语法,则可以这样做,并且仍然保持完全的类型安全:

//故意将其保留为非类型化,以便获得可能的最具体的推断类型。
常数工厂={
“整数”:(值:数字)=>新的TBase(值)作为基,
'字符串':(值:字符串)=>新的XBase(值)作为基础,
}
常量a:Base=factories['string']('thisMustBeAString');
常数b:基=工厂['integer'](54);
常量c:Base=factories['integer']('thisWillNotCompile');
const d:Base=factories['string']('neitherWillThis');
常数e:Base=factories[a.value]('norWillThis');
从该映射提取类型的一些方法:

//提取类型的名称:'integer'|'string'。
类型TypeName=工厂类型的键;
//提取工厂函数的类型,例如(值:number)=>Base。
类型工厂类型=工厂类型[T];
//提取进入工厂的参数类型。
类型FactoryArgumentType=参数[0];
//提取工厂的返回类型。
//当前始终等于它的参数类型,但不需要等于。
类型FactoryReturnType=返回类型;
使用这些,您实际上可以以一种相当丑陋的方式实现
getBase

函数getBase(类型:T,值:FactoryArgumentType):FactoryReturnType{ 将Factory[type](值为never)作为FactoryReturnType返回; }
我不太明白为什么需要奇怪的
值as never
来让编译器接受这一点,但它最终会发出正确的代码。

请共享
强制枚举器
无法复制您的代码。你能在typescript游乐场中共享它吗?@captain yossarian ImprovalEnumber实际上是来自@angular/cdk/Improval的ImprovalEnumberProperty,并将输入值强制为数字。我在游乐场中添加了一个类似的实现(文章中的链接),尝试从
getBase
函数中删除返回类型。请让我知道它是否适合你you@captain-yossarian只要删除类型就可以解析为TBase | XBase,这并不是我真正想要的响应。我早上会试试这个,然后再回答