我有一个用一个参数调用的函数。此参数是对象。此函数返回另一个对象,其中一个属性是传递给函数对象的值。当我尝试使用obj [key]表示法检索对象的值时遇到问题。
我确实知道,该密钥必须是正确的类型,才能像这样使用。我不能使用简单的键作为字符串,如果在接口中我没有[key:string]:any。但这不是问题。我的键是作为传递的对象中的键的字符串的并集:'user'| '名称'等。
interface Twitter<T> {
name: T;
user: T;
sex: T extends string ? boolean : string;
}
interface Facebook<T> {
appName: T;
whatever: T;
imjustanexapmle: T;
}
type TwFbObjKeys = keyof Twitter<string> | Facebook<string>
我的功能如下:
public static getArrayOfObjects(
queryParameters: Twitter<string> | Facebook<string>,
) {
const keys = Object.keys(queryParameters) as TwFbObjKeys[];
return keys.map((paramId) => ({
paramId,
value: queryParameters[paramId],
}));
}
我希望使用类型为'name'| “性别” | 'appName'| ...作为具有此键的对象的键,不会引发错误。但不幸的是我有错误:
TS7053:元素隐式地具有“ any”类型,因为类型为“ name”的表达式| “性别” | 'appName'| ...不能用于索引Twitter |脸书类型“ Twitter”上不存在属性“名称”脸书
我正在与它战斗几个小时。知道我该如何解决吗?
我认为您的问题来自那条线
type TwFbObjKeys = keyof Twitter<string> | Facebook<string>
// is of type type TwFbObjKeys = "name" | "user" | "sex" | Facebook<string>
您可能想要
type TwFbObjKeys = keyof Twitter<string> | keyof Facebook<string>
// of type type TwFbObjKeys = "name" | "user" | "sex" | "appName" | "whatever" | "imjustanexapmle"
(假设您是指type TwFbObjKeys = keyof Twitter<string> | keyof Facebook<string>
)
Typescript引发错误,因为paramId
具有包含两个接口的所有键的类型:
'name'| '用户'| “性别” | 'appName'| “随便什么” | 'imjustanexapmle'
但是queryParameters
只能是任一接口的类型:
'name'| '用户'| '性别'
或
'appName'| “随便什么” | 'imjustanexapmle'
要解决此问题,您应该将两种类型分开:
interface Twitter<T> {
name: T;
user: T;
sex: T extends string ? boolean : string;
}
interface Facebook<T> {
appName: T;
whatever: T;
imjustanexapmle: T;
}
function isTwitter<T>(val: Twitter<T> | Facebook<T>): val is Twitter<T> {
return (
typeof (val as Twitter<T>).name !== "undefined" &&
typeof (val as Twitter<T>).user !== "undefined" &&
typeof (val as Twitter<T>).sex !== "undefined"
)
}
function isFacebook<T>(val: Twitter<T> | Facebook<T>): val is Facebook<T> {
return (
typeof (val as Facebook<T>).appName !== "undefined" &&
typeof (val as Facebook<T>).whatever !== "undefined" &&
typeof (val as Facebook<T>).imjustanexapmle !== "undefined"
)
}
function getValue<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
function getArrayOfObjects(
queryParameters: Twitter<string> | Facebook<string>,
) {
if (isTwitter(queryParameters)) { // if queryParameters is of type Twitter<string>
const keys = Object.keys(queryParameters);
return keys.map((paramId) => ({
paramId,
value: getValue(queryParameters, paramId as keyof Twitter<string>)
}));
} else if (isFacebook(queryParameters)) { // if queryParameters is of type Facebook<string>
const keys = Object.keys(queryParameters);
return keys.map((paramId) => ({
paramId,
value: getValue(queryParameters, paramId as keyof Facebook<string>)
}));
} else { // if queryParameters is invalid
throw new Error("invalid queryParameters!")
}
}
最好将函数参数queryParameters
定义为具有约束T
而不是固定并集<T extends Twitter<string> | Facebook<string>>
的泛型queryParameters: Twitter<string> | Facebook<string>
:
function getArrayOfObjects<T extends Twitter<string> | Facebook<string>>(
queryParameters: T
) {
const keys = Object.keys(queryParameters) as (keyof T)[];
return keys.map((paramId) => ({
paramId,
value: queryParameters[paramId],
}));
}
说明
通过使用泛型,您可以为queryParameters
保留传入参数的类型,而只是确保它是Twitter<string> | Facebook<string>
的子类型。对于联合类型Twitter<string> | Facebook<string>
,queryParameters
仍将不确定,并且在函数体内仍可能是Twitter<string>
或Facebook<string>
,这会导致keyof
运算符出现问题。
您可能打算将TwFbObjKeys
定义为
// "name" | "user" | "sex" | "appName" | "whatever" | "imjustanexapmle"
type TwFbObjKeys = keyof Twitter<string> | keyof Facebook<string>
// not this: keyof only applies to Twitter<string> here: "name" | "user" | "sex" | Facebook<string>
type TwFbObjKeys_not = keyof Twitter<string> | Facebook<string>
但是那不能单独解决您的问题,因为给定联合类型,您只能访问所有组成部分的common属性键。示例:
declare const queryParameters: Twitter<string> | Facebook<string>
// type keysOfQueryParameters = never
type keysOfQueryParameters = keyof typeof queryParameters
// ok, let's try to define all union keys manually
type TwFbObjKeys = "name" | "user" | "sex" | "appName" | "whatever" | "imjustanexapmle"
declare const unionKeys: TwFbObjKeys
// error: doesn't work either, because Twitter and Facebook don't have common props
queryParameters[unionKeys]
// this would work, if both Twitter and Facebook have "common" prop
queryParameters["common"]