从隐式字典成功的地方,从类型字典获取键失败

时间:2019-02-17 01:23:52

标签: typescript

我具有以下类型定义:

airbnb = pd.DataFrame({'host_id':[1,1,1,2,2,2], 
                       'reviews_per_month':[4,5,np.nan,9,3,5],
                       'review_scores_rating':[3,np.nan,np.nan,np.nan,7,8]})
print (airbnb)
   host_id  review_scores_rating  reviews_per_month
0        1                   3.0                4.0
1        1                   NaN                5.0
2        1                   NaN                NaN
3        2                   NaN                9.0
4        2                   7.0                3.0
5        2                   8.0                5.0

使用此定义,CountryCodes成功返回以下类型:cols=['reviews_per_month','review_scores_rating'] # would work with all your columns print (airbnb.fillna(airbnb.groupby('host_id')[cols].transform('mean'))) host_id review_scores_rating reviews_per_month 0 1 3.0 4.0 1 1 3.0 5.0 2 1 3.0 4.5 3 2 7.5 9.0 4 2 7.0 3.0 5 2 8.0 5.0

但是,我想在export const countries = { US: { name: "United States" }, UK: { name: "United Kingdom" } }; export type CountryCodes = keyof typeof countries; 中输入属性值,所以我改用以下类型定义:

"US" | "UK

现在,将countries的键入定义为export interface IDictionary<T = any> { [key: string]: T; } export interface ICountry { name: string; population?: number; } export const countries: IDictionary<ICountry> = { US: { name: "United States" }, UK: { name: "United Kingdom" } };

如何在保持CountryCode类型定义的同时,在string | number结构上获得所需的更强类型?

1 个答案:

答案 0 :(得分:2)

通过预先定义密钥

此解决方案要求您预先定义用作字典中键的字符串文字。注意:如果未提供任何参数,则仅将string用作默认类型参数,而您的IDictionary的行为将与以前一样。

type IDictionary<V, K extends string = string> = {
  [Index in K]: V
}

type CountryCodes = "US" | "UK"

export const countries: IDictionary<ICountry, CountryCodes> = {
  US: {
    name: "United States"
  },
  UK: {
    name: "United Kingdom"
  }
};

通过使用额外的函数调用

在此解决方案中,我们创建了一个工厂函数,以确保我们提供的所有内容都符合特定条件。

const assert = <T>() => <U extends T>(argument: U): U => argument;

用法:

const assertCountries = assert<IDictionary<ICountry>>();

const countries = assertCountries({
  US: {
    name: "United States"
  },
  UK: {
    name: "United Kingdom"
  },
});

type CountryCodes = keyof typeof countries; // "US" | "UK"

通过删除类型定义

有时候,使用类型定义并信任TypeScript来推断对象文字的类型会更容易。通过这种方法,我们首先从数据开始,并且(如果需要的话)根据您的数据创建类型,就像开始时一样。

为了获得所需的类型安全性,我们将责任转移给您的数据使用者。在这里,foo确保其自变量符合所需的形状。

const countries = {
  US: {
    name: "United States"
  },
  UK: {
    name: "United Kingdom"
  }
};

type CountryCodes = keyof typeof countries; // "US" | "UK"

function foo<T extends IDictionary<ICountry>>(countries: T): void {
  /* ... */
}