首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Typescript:通用到特定类型

Typescript:通用到特定类型
EN

Stack Overflow用户
提问于 2020-09-01 05:24:51
回答 3查看 674关注 0票数 0

我有一个泛型类型

代码语言:javascript
复制
type GenericType = {
  [key: string]: {
    prop1: string,
    prop2?: string,
    prop3?: number,
  },
};

我使用泛型类型来帮助构建/类型检查我创建的新对象。

代码语言:javascript
复制
const Obj1: GenericType = {
  key1: {
    prop1: "hi",
  },
  key2: {
    prop1: "bye",
    prop2: "sup",
  },
};

它起作用了。然而,当我使用这个新对象时,如果不从其中删除GenericType,vscode / typescript就不会显示Obj1的键或道具。我也可以“扩展”这个类型,但这是代码重复。

代码语言:javascript
复制
Obj1.???

有没有办法保留GenericType,同时访问我从它创建的新对象中更具体的道具?

更新1

我希望vscode / typescript显示/验证

代码语言:javascript
复制
Obj1.key1.prop1
Obj1.key2.prop1

和错误,如果

代码语言:javascript
复制
Obj1.key1.prop2
Obj1.key2.prop3
Obj1.key2.prop321
EN

回答 3

Stack Overflow用户

发布于 2020-09-01 05:33:07

我认为这样做的用例是,您希望GenericType具有任何类型的字符串作为键,但仍然希望确定这些键的值在声明时可以是什么值。

在这种情况下,您可以使用Record类型将Obj1允许的键限制为您指定的键。

代码语言:javascript
复制
type GenericType<K extends string> = Record<K, {
  prop1: string,
  prop2?: string,
  prop3?: number,
}>

然后,在定义Obj1时,您可以通过将允许键的联合设置为第一个类型参数来指定允许的键应该是什么。

代码语言:javascript
复制
const Obj1: GenericType<"key1" | "key2"> = {
  key1: {
    prop1: "hi",
  },
  key2: {
    prop1: "bye",
    prop2: "sup",
  },
};

现在,TypeScript将允许您以完全类型安全的方式访问key1key2

代码语言:javascript
复制
Obj1.key1
// (property) key1: {
//     prop1: string;
//     prop2?: string | undefined;
//     prop3?: number | undefined;
// }

编辑

根据OP的评论,听起来他不愿意指定所有的键名,或者必须手动检查是否存在可选字段。

在确保声明的对象与GenericType接口的约束相匹配的情况下,我能想到的最好的方法就是这样做。

首先,您需要此实用程序类型:

代码语言:javascript
复制
type Constraint<T> = T extends Record<string, {
  prop1: string,
  prop2?: string,
  prop3?: number,
}> ? T : never

如果T与约束不匹配,则返回never,否则返回T

现在声明您实际想要的普通对象。没有类型批注。

代码语言:javascript
复制
const CorrectObj = {
  key1: {
    prop1: "hi",
  },
  key2: {
    prop1: "bye",
    prop2: "sup",
  },
};

然后将此对象文本赋值给另一个变量,但声明新变量必须是Constraint<typeof CorrectObj>类型

代码语言:javascript
复制
const CheckedObj: Constraint<typeof CorrectObj> = CorrectObj

如果CorrectObj与约束匹配,那么CheckedObj将是CorrectObj的简单副本,其中包含所有可用字段。

但是,如果对象字面量与约束不匹配,则在尝试将CheckedBadObj赋给字面量时会出现类型错误:

代码语言:javascript
复制
const BadObj = {
  key1: {
    progfdgp1: "hi",
  },
  key2: {
    prop1: "bye",
    prdfgop2: "sup",
  },
};

const CheckedBadObj: Constraint<typeof BadObj> = BadObj
//    ^^^^^^^^^^^^^
// Type '{ key1: { progfdgp1: string; }; key2: { prop1: string; prdfgop2: string; }; }' is not assignable to type 'never'. (2322)

解释是,当T不匹配时,Constraint<T>never,但是您仍然试图将非never值赋给CheckedBadObj,从而导致类型冲突!

这涉及到声明每个object文本的两个实例时的一些重复,但这是唯一的方法

让TypeScript确切地知道对象上存在哪些字段,包括所有子对象,同时让

  1. 让你的“泛型”类型的值与你的约束匹配( still
  2. checking

您可以在playground中尝试这种方法。

票数 2
EN

Stack Overflow用户

发布于 2020-09-01 05:47:50

假设您的目标是让key1key2显示在Obj1的自动完成菜单中,但仍然可以在以后设置其他关键点,下面是一个可能的解决方案:

代码语言:javascript
复制
type GenericType = {
  [key: string]: {
    prop1: string,
    prop2?: string,
    prop3?: number,
  };
};

const generify = <T extends GenericType>(obj: T): T & GenericType => obj;

const Obj1 = generify({
  key1: {
    prop1: "hi",
  },
  key2: {
    prop1: "bye",
    prop2: "sup",
  },
});

我现在想不出一个更简单的解决方案,可以在GenericType和只包含key1key2属性的特定类型之间为Obj1提供相同的交集类型。

票数 1
EN

Stack Overflow用户

发布于 2020-09-07 08:11:45

使用通用实用程序函数(enforce),该函数

  • 使用泛型约束确保对象与GenericType匹配(extends)
  • and返回传入对象的类型以进行类型推断。

代码:

代码语言:javascript
复制
type GenericType = {
  [key: string]: {
    prop1: string,
    prop2?: string,
    prop3?: number,
  };
};

const enforce = <T extends GenericType>(obj: T): T => obj;

工作解决方案:

代码语言:javascript
复制
type GenericType = {
  [key: string]: {
    prop1: string,
    prop2?: string,
    prop3?: number,
  };
};

const enforce = <T extends GenericType>(obj: T): T => obj;

const Obj1 = enforce({
  key1: {
    prop1: "hi",
  },
  key2: {
    prop1: "bye",
    prop2: "sup",
  },
});


Obj1.key1.prop1; // Ok
Obj1.key2.prop1; // Ok

/** 
 * ERROR: does not match passed in object
 */
Obj1.key1.prop2 // Error 
Obj1.key2.prop3 // Error
Obj1.key2.prop321 // Error

Obj1.key3; // Error 

/**
 * ERRORS: Does not match GenericType
 */
const Obj2 = enforce({
  key1: { // Error 
  }
});
const Obj3 = enforce({
  key1: {
    prop1: 123, // Error
  }
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63678380

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档