Typescript泛型:如何将数组条目映射到对象键

时间:2019-08-15 13:20:37

标签: typescript typescript-generics

TLDR:在我的通用函数中,我想拥有 myFunction(['width', 'left'])返回类型{width: string, left: string}

长版:

我有一个Typescript函数,该函数具有一个字符串数组作为输入,并返回一个以数组键为值的对象:

export interface Dictionary<T> {
  [index: string]: T | undefined;
}
var getStyle = function (  
  element: Element,
  propertyNames: readonly string[]
) { 
  let gCS= window.getComputedStyle(element)
  let result: Dictionary<string> = {};
  propertyNames.forEach((prop)=>{
    result[prop]=gCS.getPropertyValue(prop);
  });
  return result;
};    

打字稿的返回值是一个对象/字典,但没有特定的属性。

var resultObj = getStyle(document.body, ['width']);
resultObj.width; // should be ok
resultObj.height; // should be not ok

我尝试了很多事情。最好的是那个:

export type RestrictedDictionary1<T, P extends readonly string[]> = {
    [index in keyof P]?: T | undefined
}
declare function getStyle1<P extends readonly string[]>(  
    element: Element,
    propertyNames: P
): RestrictedDictionary1<string, P>;

var resultObj1 = getStyle1(document.body, ['width']);  // Huh? Why an array
resultObj1.width; // should be ok, but both are unvalid for TS
resultObj1.height; // should be not ok, but both are unvalid for TS

Typescript现在从中得到一个数组。我不知道为什么。

最后一次尝试再次使用interface,但是[index in P]部分无效

export interface RestrictedDictionary2<T, P extends string[]> {
    [index in P]: T | undefined;  // A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.
}
declare function getStyle2<P extends string[]>(  
    element: Element,
    propertyNames: P
): RestrictedDictionary2<string, P>;

var resultObj2 = getStyle2(document.body, ['width']);
resultObj2.width; // should be ok
resultObj2.height; // should be not ok

1 个答案:

答案 0 :(得分:2)

尽管您认为语法有点不对劲,但您的看法非常接近。如果Pstring[],则keyof P只是数组的成员,而不是值。您可以使用P[number]来获取数组中值的类型。另外,接口不能包含映射类型([index in P]: ...语法),只有类型别名可以(type定义)。还有一个名为Record的预定义映射类型,正是您不需要定义新的映射类型


var getStyle = function<T extends string> (  
  element: Element,
  propertyNames: readonly T[]
): Record<T, string> { 
  let gCS= window.getComputedStyle(element)
  let result = {} as Record<T, string>;
  propertyNames.forEach((prop)=>{
    result[prop]=gCS.getPropertyValue(prop);
  });
  return result;
};   
var resultObj = getStyle(document.body, ['width']);
resultObj.width; // should be ok
resultObj.height; // err

Play