首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何让TypeScript知道我的对象的键?

如何让TypeScript知道我的对象的键?
EN

Stack Overflow用户
提问于 2020-09-17 14:10:48
回答 2查看 188关注 0票数 0

我使用TypeScript输入以下内容:

代码语言:javascript
复制
const k = {
  container: {
   width: '100%',
  },
}

当我使用智能感知时,TypeScript发现我的对象k有一个名为container的属性似乎很酷。它工作得很好。现在,我想限制属性的值,所以我声明了一个接口:

代码语言:javascript
复制
interface StyleSet {
   [key: string]: React.CSSProperties
}

现在我将类型添加到前面的对象中,所以我们有:

代码语言:javascript
复制
const k: StyleSet = {
  container: {
   width: '100%',
  },
}

一切都很好。现在,智能感知可以识别,并且TypeScript强制对象k的属性值为React.CSSProperties类型。

然而,现在问题来了,现在智能感知(和TypeScript!?)不再识别我的k对象中的属性名称。也就是说,当我输入k.时,它不会提示(也似乎忽略)我之后输入的内容。所以我可以输入k.potatoe并使用这个值,没有任何问题(当然,这个值是undefined / null ),但是TypeScript不再提示任何错误。

问:我如何告诉TypeScript,属性的值都是React.CSSProperties类型的,但是当我使用对象时,仍然限制属性的名称?也就是说,我只能输入k.container

我在网上搜索了大量的TypeScript文档和示例,但似乎这是不可能的。我尝试过接口、类型、记录、ReadOnly……

请注意,对象的键是未知的。例如,其中一个可能是:

代码语言:javascript
复制
const a: StyleSet = {
  potato:{
    width: '100%',
  },
}

而另一个对象可能是:

代码语言:javascript
复制
const b: StyleSet = {
  ketchup: {
    width: 'auto',
  },
}

另请注意,这里有一个部分解决方案,使用ReturnType TypeScript可以做我想做的事情,但我需要将每个对象包装在一个函数中。我也觉得这是无稽之谈。

欢迎任何想法:)

EN

回答 2

Stack Overflow用户

发布于 2020-09-17 14:51:28

这里有一种方法:

代码语言:javascript
复制
type PossibleKeys = 'container' | 'foo' | 'bar';

type StyleSet = {
    // Question mark makes them optional properties.
    // Otherwise TypeScript will require all keys in `PossibleKeys` to present.
    [key in PossibleKeys]?: React.CSSProperties
}

const k: StyleSet = {
    container: {
        width: '100%',
    },
}

// Now when you type `k.`, you will see three suggestions listed above.

在此Playground Link中尝试。

更新

好的,你真正想要的是一组动态的键,基于给定的对象文字,并且你已经知道函数的解决方案,但是你不想使用它。然而,似乎在当前TypeScript的限制下,根本不可能存在更好的解决方案,原因如下。

首先,很明显,如果两个对象属于相同的(非泛型)类型,那么它们必须具有完全相同的成员(可能是可选的,但仍然是相同的键集)。因此,让不同的对象在以后有不同的键约束的唯一可能方式,就是让它们具有技术上不同的类型。显然,泛型类型将是您的最佳选择,其中泛型参数会导致不同的键约束。

因此,假设我们这样定义一个泛型类型:

代码语言:javascript
复制
type StyleSet<T extends string> = {
    [k in T]: React.CSSProperties;
}

但是,至少由于目前TypeScript的局限性,如果不使用函数,它就不能自动推断通用参数。例如,您不能这样写:

代码语言:javascript
复制
const a: StyleSet<> = ... // generic parameter must be explicitly given here

因为目前还没有“部分类型推断”这样的东西;类型推断只有在我们完全省略了类型,并且可以从赋值的值中推断出来的时候才有效。如您所知,一种可能性是我们的函数解决方案:

代码语言:javascript
复制
function set<T extends string>(s: StyleSet<T>) { return s; }

const a = set({
    container: {
        width: "100%"
    }
});

然后,在本例中,我们的a被推断为StyleSet<"containter">。是的,您必须将每个对象文字包装在我们的函数set()中,但是正如我们刚才所分析的,您唯一的选择是显式地给出泛型参数:

代码语言:javascript
复制
const a: StyleSet<"container"> = {
    container: {
        width: "100%"
    }
};

这显然更糟糕,特别是当你在一个实例中有多个键的时候。有了函数解决方案,所有的键都会一次推断出来:

代码语言:javascript
复制
const b = set({
    propA: { ... },
    propB: { ... }
});
// b will become StyleSet<"propA" | "propB">
票数 1
EN

Stack Overflow用户

发布于 2020-09-17 14:16:37

您正在创建StyleSet Index Type。如果仔细观察它,它不知道任何关于键的确切名称,它只知道,键可以是任何字符串。

Typescript也知道这么多信息。当您将StyleSet赋值给const k时,您丢失了密钥名称的信息。在代码的后面,typescript并不知道k包含container字段。

您可以做的是,如果您知道应该在StyleSet中提供的键的静态列表,那么您可以在类型本身中捕获它。使用索引类型,您将无法静态地访问它的字段。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63932202

复制
相关文章

相似问题

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