使用打字稿键入对象数组:
以下是接口:
export interface IUser {
id: string;
order: number;
}
export interface IUsersLogin {
result: number;
UserId: string;
}
export interface IUsersUsers {
id: number;
order: number;
}
export interface IOriginalData {
Users?: IUser[];
UsersLogins?: IUsersLogin[];
UsersUsers?: IUsersUsers[];
}
在这里,我使用以下接口创建对象:
const originalData: IOriginalData = {
Users: [
{
id: "e4e2bb46-c210-4a47-9e84-f45c789fcec1",
order: 1
},
{
id: "b95274c9-3d26-4ce3-98b2-77dce5bd7aae",
order: 2
}
],
UsersLogins: [
{
result: 1,
UserId: "e4e2bb46-c210-4a47-9e84-f45c789fcec1"
},
{
result: 0,
UserId: "b95274c9-3d26-4ce3-98b2-77dce5bd7aae"
}
],
UsersUsers: [
{
id: 1,
order: 0
},
{
id: 2,
order: 0
}
]
};
在这里,我操纵该对象的数据以将其推入另一个对象:
interface IPushedDataItem {
data: IUser | IUsersLogin | IUsersUsers;
}
type TypePushedData = Array<IPushedDataItem>;
let pushedData: TypePushedData = [];
Object.keys(originalData).forEach(item => {
pushedData.push({
data: originalData[item]
});
});
在此过程中,我无法正确键入pushedData
,并且它抱怨data:originalData[item]
。
您可以在TypeScript玩法中找到它:
任何帮助都将受到欢迎!
答案 0 :(得分:1)
originalData
的定义以支持索引器:const originalData: IOriginalData & { [key: string]: (IUser | IUsersLogin | IUsersUsers)[] }
pushedData
时,您必须遍历键访问的项数组,因为它不是单个项:Object.keys(originalData).forEach(item => {
const subItems = originalData[item];
if (subItems) {
for (const subItem of originalData[item]) {
pushedData.push({
data: subItem
});
}
}
});
总体代码如下:
export interface IUser {
id: string;
order: number;
}
export interface IUsersLogin {
result: number;
UserId: string;
}
export interface IUsersUsers {
id: number;
order: number;
}
export interface IOriginalData {
Users?: IUser[];
UsersLogins?: IUsersLogin[];
UsersUsers?: IUsersUsers[];
}
const originalData: IOriginalData & { [key: string]: (IUser | IUsersLogin | IUsersUsers)[] } = {
Users: [
{
id: "e4e2bb46-c210-4a47-9e84-f45c789fcec1",
order: 1
},
{
id: "b95274c9-3d26-4ce3-98b2-77dce5bd7aae",
order: 2
}
],
UsersLogins: [
{
result: 1,
UserId: "e4e2bb46-c210-4a47-9e84-f45c789fcec1"
},
{
result: 0,
UserId: "b95274c9-3d26-4ce3-98b2-77dce5bd7aae"
}
],
UsersUsers: [
{
id: 1,
order: 0
},
{
id: 2,
order: 0
}
]
};
interface IPushedDataItem {
data: IUser | IUsersLogin | IUsersUsers;
}
type TypePushedData = Array<IPushedDataItem>;
let pushedData: TypePushedData = [];
Object.keys(originalData).forEach(item => {
const subItems = originalData[item];
if (subItems) {
for (const subItem of originalData[item]) {
pushedData.push({
data: subItem
});
}
}
});
更新
如果您想更严格地检查字符串键,可以使用in keyof
语法进行定义:
const originalData: IOriginalData & { [key in keyof IOriginalData]: (IUser | IUsersLogin | IUsersUsers)[] }
尽管还需要将Object.keys(originalData)
的结果强制转换为(keyof IOriginalData)[]
。
总体代码如下:
export interface IUser {
id: string;
order: number;
}
export interface IUsersLogin {
result: number;
UserId: string;
}
export interface IUsersUsers {
id: number;
order: number;
}
export interface IOriginalData {
Users?: IUser[];
UsersLogins?: IUsersLogin[];
UsersUsers?: IUsersUsers[];
}
export type OriginalDataUnion = IUser | IUsersLogin | IUsersUsers;
const originalData: IOriginalData & { [key in keyof IOriginalData]: OriginalDataUnion[] } = {
Users: [
{
id: "e4e2bb46-c210-4a47-9e84-f45c789fcec1",
order: 1
},
{
id: "b95274c9-3d26-4ce3-98b2-77dce5bd7aae",
order: 2
}
],
UsersLogins: [
{
result: 1,
UserId: "e4e2bb46-c210-4a47-9e84-f45c789fcec1"
},
{
result: 0,
UserId: "b95274c9-3d26-4ce3-98b2-77dce5bd7aae"
}
],
UsersUsers: [
{
id: 1,
order: 0
},
{
id: 2,
order: 0
}
]
};
interface IPushedDataItem {
data: OriginalDataUnion;
}
type TypePushedData = Array<IPushedDataItem>;
let pushedData: TypePushedData = [];
for (const item of Object.keys(originalData) as (keyof IOriginalData)[]) {
const subItems = originalData[item];
if (subItems) {
for (const subItem of subItems) {
pushedData.push({
data: subItem
});
}
}
}
答案 1 :(得分:0)
那里有两个问题。
originalData
没有索引签名。通常,由于TypeScript的静态键入性质,因此高度动态的代码(例如使用Objct.keys
通过名称遍历对象的所有属性的代码)往往会出现问题,因为这些属性会丢失静态类型信息具有不同的值类型。如果您可以这样做,那么可能会更好。
另一个问题是,您给pushedData
提供了一种类型,该类型期望具有data
属性的对象数组,但是您的代码没有这样做,它会推入IUser
等对象直接放入数组,而不是将data
属性为该IUser
等对象的对象压入数组。我怀疑您是说IPushedDataItem
是:
type IPushedDataItem = IUser | IUsersLogin | IUsersUsers;
假设我对此表示正确,则可以这样创建pushedData
:
let pushedData: TypePushedData = [
...(originalData.Users ? originalData.Users : []),
...(originalData.UsersLogins ? originalData.UsersLogins : []),
...(originalData.UsersUsers ? originalData.UsersUsers : []),
];
这还具有为您为结果数组中的条目提供已定义顺序的优点(而对于Object.keys
,则没有按规范保证顺序的顺序,尽管所有现代引擎对于自己的属性都遵循相同的顺序就像他们对getOwnPropertyKeys
所做的那样,只是不能保证。
如果您将属性设置为非可选(将?
中的属性中的IOriginalData
删除了,则情况就不会那么复杂了)。那将是:
let pushedData: TypePushedData = [
...originalData.Users,
...originalData.UsersLogins,
...originalData.UsersUsers,
];
如果您确实希望对象具有data
属性(您的原始版本IPushedDataItem
),则可以使用map
:
let pushedData: TypePushedData = [
...(originalData.Users ? originalData.Users.map(data => ({data})) : []),
...(originalData.UsersLogins ? originalData.UsersLogins.map(data => ({data})) : []),
...(originalData.UsersUsers ? originalData.UsersUsers.map(data => ({data})) : []),
];
...如果属性不是可选的,那么再次简化。
答案 2 :(得分:0)
让我们简化一下示例:
export interface A { s: string }
export interface B { n: number }
export interface C { b: boolean }
export interface All {
A: A;
B: B;
C: C;
}
//
let all: All = {
A: {s: "s"},
B: {n: 33},
C: {b: true},
};
let other: Array<A | B | C> = [];
现在,这个
Object.keys(all).forEach(k => other.push(all[k]))
将失败,因为Object.keys
被推断为Array<string>
,而不是人们所期望的Array<keyof All>
。有关原因,请参见this comment。
但是,同一评论指出for k in obj
在使用泛型时将k
推断为keyof
。我们可以使用它来编写我们自己的Object.keys
的严格版本:
function strictKeys<T>(o: T): Array<keyof T> {
let a = [];
for (let k in o)
a.push(k);
return a;
}
现在
strictKeys(all).forEach(k => other.push(all[k]))
计算正确!