我想在Typescript对象中存储string ->字符串的映射,并强制所有值映射到字符串。例如:

var stuff = {};
stuff["a"] = "foo";   // okay
stuff["b"] = "bar";   // okay
stuff["c"] = false;   // ERROR!  bool != string

是否有一种方法让我强制值必须是字符串(或任何类型..)?


当前回答

interface AccountSelectParams {
  ...
}
const params = { ... };

const tmpParams: { [key in keyof AccountSelectParams]: any } | undefined = {};
  for (const key of Object.keys(params)) {
    const customKey = (key as keyof typeof params);
    if (key in params && params[customKey] && !this.state[customKey]) {
      tmpParams[customKey] = params[customKey];
    }
  }

如果你明白这个概念,请评论

其他回答

基于@shabunc的答案,这将允许将键或值(或两者都是)强制为您想强制的任何值。

type IdentifierKeys = 'my.valid.key.1' | 'my.valid.key.2';
type IdentifierValues = 'my.valid.value.1' | 'my.valid.value.2';

let stuff = new Map<IdentifierKeys, IdentifierValues>();

也应该使用enum而不是类型定义。

你可以传递一个名字给未知键,然后写你的类型:

type StuffBody = {
  [key: string]: string;
};

现在你可以在你的类型检查中使用它:

let stuff: StuffBody = {};

但对于FlowType,不需要有名称:

type StuffBody = {
  [string]: string,
};

定义接口

interface Settings {
  lang: 'en' | 'da';
  welcome: boolean;
}

强制键为设置界面的特定键

private setSettings(key: keyof Settings, value: any) {
   // Update settings key
}

@Ryan Cavanaugh的回答完全没问题,而且仍然有效。值得补充的是,在16年秋季,当我们可以宣称ES6被大多数平台支持时,当你需要将一些数据与一些键关联时,几乎总是更好地坚持使用Map。

当我们写let a: {[s:字符串]:字符串;}我们需要记住typescript编译后没有类型数据这样的东西,它只用于编译。和{[s:字符串]:字符串;}将编译为{}。

也就是说,即使你写的是:

class TrickyKey  {}

let dict: {[key:TrickyKey]: string} = {}

这只是不会编译(即使对于目标es6,你也会得到错误TS1023:索引签名参数类型必须是'string'或'number'。

实际上,字符串或数字作为潜在的键是有限的,所以这里没有太多强制类型检查的意义,特别是要记住,当js试图通过数字访问key时,它会将其转换为字符串。

因此,假设最佳实践是使用Map,即使键是字符串,这是相当安全的,所以我坚持使用:

let staff: Map<string, string> = new Map();
interface AgeMap {
    [name: string]: number
}

const friendsAges: AgeMap = {
    "Sandy": 34,
    "Joe": 28,
    "Sarah": 30,
    "Michelle": "fifty", // ERROR! Type 'string' is not assignable to type 'number'.
};

在这里,接口AgeMap强制键为字符串,值为数字。关键字名称可以是任何标识符,应该用于建议接口/类型的语法。

你可以使用类似的语法来强制一个对象对union类型中的每个条目都有一个键:

type DayOfTheWeek = "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday";

type ChoresMap = { [day in DayOfTheWeek]: string };

const chores: ChoresMap = { // ERROR! Property 'saturday' is missing in type '...'
    "sunday": "do the dishes",
    "monday": "walk the dog",
    "tuesday": "water the plants",
    "wednesday": "take out the trash",
    "thursday": "clean your room",
    "friday": "mow the lawn",
};

当然,您也可以将其设置为泛型类型!

type DayOfTheWeek = "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday";

type DayOfTheWeekMap<T> = { [day in DayOfTheWeek]: T };

const chores: DayOfTheWeekMap<string> = {
    "sunday": "do the dishes",
    "monday": "walk the dog",
    "tuesday": "water the plants",
    "wednesday": "take out the trash",
    "thursday": "clean your room",
    "friday": "mow the lawn",
    "saturday": "relax",
};

const workDays: DayOfTheWeekMap<boolean> = {
    "sunday": false,
    "monday": true,
    "tuesday": true,
    "wednesday": true,
    "thursday": true,
    "friday": true,
    "saturday": false,
};

10.10.2018更新: 看看下面@dracstaxi的答案——现在有一个内置的类型Record,它可以帮你完成大部分工作。

1.2.2020更新: 我已经完全从我的回答中删除了预先制作的映射接口。@dracstaxi的回答让他们完全无关紧要。如果您仍然想使用它们,请检查编辑历史记录。