Typescript-联合约束导致不需要的类型加宽

Typescript-联合约束导致不需要的类型加宽,typescript,Typescript,另一个推论问题。我试图防止Typescript在对象中嵌入联合类型时丢失正确推断的类型信息。情况如下: 两个接口Foo和Moo及其联合FooMoo: interface Foo { goo: string} interface Moo { goo: number} type FooMoo = Foo | Moo const foo: Foo = {goo: "bar"} const moo: Moo = {goo: 1} 以及至少包含以下各项之一的混合对象: const

另一个推论问题。我试图防止Typescript在对象中嵌入联合类型时丢失正确推断的类型信息。情况如下:

两个接口Foo和Moo及其联合FooMoo:

interface Foo { goo: string}
interface Moo { goo: number}
type FooMoo = Foo | Moo

const foo: Foo = {goo: "bar"}
const moo: Moo = {goo: 1}
以及至少包含以下各项之一的混合对象:

const mixedObject = {
    foo,
    moo
}
现在,很明显,TS知道foo和moo的正确类型,所以这里没有问题:

let fooToo: Foo
let mooToo: Moo

fooToo = mixedObject.foo
mooToo = mixedObject.moo
但是现在让我们假设我想告诉TS,mixedObject应该仅限于foos和moos。这个限制显然会导致TS失去区分foo和moo的能力,因此出现以下代码错误:

type ManyFooMoos = {[K:string]: FooMoo}
const mixedObjectToo: ManyFooMoos = {
    foo,
    moo
}

// TS errors here because it can't narrow foo to Foo and moo to Moo;
// it just knows they are both FooMoos
fooToo = mixedObjectToo.foo
mooToo = mixedObjectToo.moo
同样的事情也会以其他方式出现,其中导致TS丢失信息的mixedObject上的约束更为间接。例如:

interface ExportedObject {
    manyFooMoos: ManyFooMoos
} 

const exportedObject: ExportedObject = {
    manyFooMoos: mixedObject
}

fooToo = exportedObject.manyFooMoos.foo
所以,我的基本问题是-我如何保持对mixedObject的约束,即它的所有属性都必须是Foos或Moos,而不丢失mixedObject中那些Foos或Moos的特定类型


完整代码已打开。

您可以通过使用标识函数+泛型来实现这一点。这将允许保留约束并防止类型加宽:

const createFooMoos = <T extends ManyFooMoos>(fooMoos: T) => fooMoos;

const mixedObjectToo = createFooMoos({
    foo,
    moo
}) // { foo: Foo, moo: Moo }

您可以通过使用identity函数+泛型来实现这一点。这将允许保留约束并防止类型加宽:

const createFooMoos = <T extends ManyFooMoos>(fooMoos: T) => fooMoos;

const mixedObjectToo = createFooMoos({
    foo,
    moo
}) // { foo: Foo, moo: Moo }

你不能,这是应该发生的。您不再获得推断类型,而是通过字符串到Foo或Moo的映射来访问它。这是为什么?换句话说,为什么我通过字符串索引访问它会导致TS失去推断?当我通过无约束对象mixedObject访问它时,这不会发生,它也是一个字符串索引,尽管是字符串文本。因为推断出的无约束类型是{foo:foo,moo:moo},比显式的{[key:string]:foo | moo}窄。它不会意外地失去推论,是你做的。你不能,这是应该发生的。您不再获得推断类型,而是通过字符串到Foo或Moo的映射来访问它。这是为什么?换句话说,为什么我通过字符串索引访问它会导致TS失去推断?当我通过无约束对象mixedObject访问它时,这不会发生,它也是一个字符串索引,尽管是字符串文本。因为推断出的无约束类型是{foo:foo,moo:moo},比显式的{[key:string]:foo | moo}窄。它不会意外地失去推理,你做到了。我要确保我理解这个解决方案是有效的,因为它基本上克服了@jonrsharpe指出的问题,即许多Foomoos的精确度也不如推断的MixedObject类型。但这意味着,也要使用特定类型的MixedObject,即T,只要它扩展了更一般的类型ManyFooMoos。因此,现在我推断的mixedObjectToo类型是更具体的类型,但它也遵循extends子句的约束。这种理解正确吗?是的,约束应用于函数参数,所以您只能传递扩展了许多oomoos的内容。另一方面,传递的参数类型是由于泛型而推断的,并用作返回类型,因此我确保我理解此解决方案是有效的,因为它基本上克服了@jornsharpe指出的问题,即许多oomoos的精度也不如mixedobjects的推断类型。但这意味着,也要使用特定类型的MixedObject,即T,只要它扩展了更一般的类型ManyFooMoos。因此,现在我推断的mixedObjectToo类型是更具体的类型,但它也遵循extends子句的约束。这种理解正确吗?是的,约束应用于函数参数,所以您只能传递扩展了许多oomoos的内容。另一方面,传递的参数类型是由于泛型而推断的,并用作返回类型