Typescript 使用工厂方法和已知输入参数进行扩展类型检查
请原谅我的标题可能不好,不知道如何描述: 我有接口A和B:Typescript 使用工厂方法和已知输入参数进行扩展类型检查,typescript,Typescript,请原谅我的标题可能不好,不知道如何描述: 我有接口A和B: interface A { prop1: string prop2: object } interface B { prop3: number } interface C extends A { prop2: { objectProperty: string } } function func1(arg1: string, arg2: object): A { ret
interface A {
prop1: string
prop2: object
}
interface B {
prop3: number
}
interface C extends A {
prop2: {
objectProperty: string
}
}
function func1(arg1: string, arg2: object): A {
return {
prop1: arg1,
prop2: arg2
}
}
function func2(arg1: number): B {
return {
prop3: arg1
}
}
界面C,进一步细化了A:
interface A {
prop1: string
prop2: object
}
interface B {
prop3: number
}
interface C extends A {
prop2: {
objectProperty: string
}
}
function func1(arg1: string, arg2: object): A {
return {
prop1: arg1,
prop2: arg2
}
}
function func2(arg1: number): B {
return {
prop3: arg1
}
}
然后我有一个函数,返回类型为A的对象:
interface A {
prop1: string
prop2: object
}
interface B {
prop3: number
}
interface C extends A {
prop2: {
objectProperty: string
}
}
function func1(arg1: string, arg2: object): A {
return {
prop1: arg1,
prop2: arg2
}
}
function func2(arg1: number): B {
return {
prop3: arg1
}
}
另一个返回类型为B的对象:
interface A {
prop1: string
prop2: object
}
interface B {
prop3: number
}
interface C extends A {
prop2: {
objectProperty: string
}
}
function func1(arg1: string, arg2: object): A {
return {
prop1: arg1,
prop2: arg2
}
}
function func2(arg1: number): B {
return {
prop3: arg1
}
}
最后是一个函数,它应该返回C或B类型的对象,并使用前两个函数构建它们:
function func3(): C | B {
if(...) {
return func1('some string', { objectProperty: 'another string' });
} else {
return func2(100);
}
}
我想要实现的是,确保第一个分支的返回值与类型C进行检查,如果没有检查,则得到警告。例如:
return func1('some string', { someOtherProperty: 'another string' });
应产生警告,因为类型C中不存在someOtherProperty
不确定这是否有意义。。。这背后的原因是,我有多个接口扩展了一个,我希望有一个工厂方法来使用给定的输入对象构建它们,并且仍然能够确保生成的对象是我想要的。可能只是因为我想把一个简单的问题变成一个复杂的问题。。。但是我想这样应该是可能的?我将更改示例代码以突出这个问题。这里我们有一个接口
A
,以及它的两个不同扩展B
和C
,其中A
中的一个属性被缩小:
interface A {
prop1: string
prop2: object
}
interface B extends A {
prop2: {
bProp: string;
}
}
interface C extends A {
prop2: {
cProp: string
}
}
函数makeA
接受与A
的prop1
和prop2
对应的参数,并返回A
类型的值:
function makeA(arg1: string, arg2: object): A {
return {
prop1: arg1,
prop2: arg2
}
}
但是,如果我们试图使用它来生成强类型的B
和C
实例,我们就会遇到问题:
function makeBOrC(): B | C {
if (Math.random() < 0.5) {
return makeA('', { bProp: '' }); // error! A is not assignable to B | C
} else {
return makeA('', { cProp: '' }); // error! A is not assignable to B | C
}
}
as B
和as C
告诉编译器将它认为的仅仅是类型A
并分别将其视为AB
或AC
。这会使错误消失。但是请注意,当您使用类型断言时,您正在将验证类型安全性的责任从编译器转移到您身上。如果你犯了一个错误,最后对编译器撒谎,它就抓不住了。。。因此,类型断言最好谨慎使用。上面带有{oops:123}
的一行显示了这样一种情况,即我们对编译器撒谎,并且没有错误
修正2:泛型 但是,对于本例,修复方法是在第二个参数的类型
T
中生成makeA()
:
function makeA<T extends object>(arg1: string, arg2: T) {
return {
prop1: arg1,
prop2: arg2
}
}
因此,makeA()
的输出类型取决于arg2
的输入类型,因此应该可以跟踪arg2
的类型。请注意,没有明确说明makeA()
生成A
;但你会发现,打字脚本使得这种明确性变得不必要。编译器理解makeA()
生成可分配给A
的值:
function foo<T extends object>(x: T) {
const a: A = makeA("", x); // okay
}
在这里,您可以看到编译器对带有bProp
和cProp
的行很满意,因为它知道它们生成了可分配给B | C
的内容。更好的是,带有oops
的行会导致一个错误:编译器通过警告您输出类型不可分配给B | C
来维护类型安全
编译器不知道
func1()
返回类型为C
的值。如果您希望这是真的,您需要更改它的类型签名,可能类似于。这能满足你的需要吗?如果是的话,我会写一个答案;如果没有,请详细说明,提供一个例子,说明什么应该成功,什么应该失败。祝你好运那可能行得通。问题是,func1
将返回许多扩展类型。签名不好看。然后又一次不确定这个想法是否有什么好处:-)也许你希望func1()
像那样是泛型的?一个好的解决方案应该有足够的用例信息,这样就可以直观地看到一个提议的解决方案是否满足您的需求。如果您有多个扩展A
的接口,并且需要func1()
根据其输入输出所有接口,则至少显示其中的两个接口。这正是我所需要的,您完成了示例!非常感谢,很抱歉没有提供更好的第一手例子。我仍然在学习typescript,我试图找出如何使用泛型来完成它,但我没能把它做好。你想回答这个问题,我会接受它,还是我应该自己回答(当然是你的功劳)?