我正在try 通过类型脚本泛型元组将多个类型映射为一个组合类型.我想看到的例子是:

// object 1
const foo = {
  user: {
    id: 1,
  },
};
// object 2
const bar = {
  hello: 'goodbye',
};

// later, after some code that combines the above objects into one
const baz = {
  user: {
    id: 1,
  },
  hello: 'goodbye',
};

我已经在泛型元组方面取得了一些进展,尽管在我try 创建对象时,TypeScrip语言服务器正确地自动完成,但当我之后try 使用映射的属性时,它会出错:

const foo = {
  user: {
    id: 1,
  },
};
const bar = {
  hello: "goodbye",
};

type Test<T extends Record<PropertyKey, any>[]> = (
  T[number] extends any ? (k: T[number]) => void : never
) extends (k: infer I) => void
  ? I
  : never;

const test: Test<[typeof foo, typeof bar]> = {
  user: {
    id: 1
  },
  hello: "23",
};

console.log(test.user);
                  ^
/* Property 'user' does not exist on type '{ user: { id: number; }; } | { hello: string; }'.
  Property 'user' does not exist on type '{ hello: string; }'.ts(2339) */

我声明的类型是传递给它的所有泛型元组的映射,当我从给定的类型创建新对象时,它会正确地自动完成,但当我try 访问这些属性时,它会错误!

这有什么不起作用的原因吗,或者我没有正确地打字?

推荐答案

问题是,您的测试类型会生成一个联合类型.当您有一个联合类型并且想要访问它的属性时,您必须让TypeScrip编译器相信访问该属性是安全的.执行此操作的方法是创建type guard,以确保对象上存在该属性.但从您的问题可以理解,您不想拥有联合类型,您的对象将具有源对象的所有属性.因此,您需要一个交叉点类型.因此,在这个伟大的SOanswer中给出的实用程序类型(UnionToIntersection)会对您有所帮助.

在实际操作中,同时键入防护和实用程序类型:

type UnionToIntersection<U> =
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

type TestUnion<T extends Record<PropertyKey, any>[]> = T[number];


type TestIntersection<T extends Record<PropertyKey, any>[]> = UnionToIntersection<T[number]>;

const test: TestUnion<[typeof foo, typeof bar]> = { user: { id: 3 }, hello: 'sd' };

const test2: TestIntersection<[typeof foo, typeof bar]> = { user: { id: 3 }, hello: 'sd' };

if (isFoo(test)) {
    if (test.user) { // is fine

    } else if (test.hello) { // not accessable

    }
}


if (test2.hello) {
    if (test2.user) { // both accessable

    }
}

function isFoo(val: any): val is typeof foo {
    return val.user

}

Playground

Edit

直接构建交叉点类型可能更好,但使用已经创建的实用程序类型似乎要容易得多.

Typescript相关问答推荐

返回签名与其他类型正确的函数不同的函数

如何使用属性作为具有Generics的TypScript类中的类型守护?

泛型函数即使没有提供类型

泛型类型,引用其具有不同类型的属性之一

如何推断计算逻辑的类型

如何使用泛型自动推断TS中的类型

访问继承接口的属性时在html中出错.角形

将带点的对象键重新映射为具有保留值类型的嵌套对象

是否可以判断某个类型是否已合并为内部类型?

转换器不需要的类型交集

为什么我的导航在使用Typescript的React Native中不起作用?

缩小对象具有某一类型的任意字段的范围

类型脚本-处理值或返回值的函数

抽象类对派生类强制不同的构造函数签名

重写返回任何

垫子工具栏不起作用的Angular 布线

如何使函数参数数组不相交?

来自枚举的<;复选框和组件列表

如何在Vue动态类的上下文中解释错误TS2345?

将对象数组传递给 Typescript 中的导入函数