ReactJS和TypeScript。我的总体目标是创建一个单一的事件处理函数,该函数接受输入元素的名称(选择,输入等),并根据属性名称以及事件的值来设置复杂对象的属性。>
本质上,类似this:
handleChange = idx => e => {
const { name, value } = e.target;
const rows = [...this.state.rows];
rows[idx] = {
[name]: value
};
this.setState({
rows
});
};
但是,就我而言,我正在使用TypeScript,并且我还使用了一个相当复杂的对象。
以下是一些测试代码:(参考Using Type Parameters in Generic Constraints)
export interface ITraveler {
id: number;
dob: Date;
tripCost: number;
firstName: string;
lastName: string;
}
export enum CoverageType {
Standard,
Plus,
}
export default interface IQuoteInfo {
country: string;
state: { fullname: string; abbreviation: string };
travelDates: {
fromDate: Date;
toDate: Date;
};
travelerInfo: ITraveler[];
paymentInfo: {
initialDate: Date;
finalDate: Date | null;
};
coverageType: CoverageType;
tripInfo: {
name: string;
program: string;
};
contactInfo: {
firstName: string;
lastName: string;
address1: string;
address2: string;
city: string;
state: string;
zip: string;
country: string;
phone: string;
email: string;
};
setQuoteInfo: (e: any) => void;
}
const initialQuoteInfo: IQuoteInfo = {
country: "USA",
state: {
fullname: "New York",
abbreviation: "NY",
},
travelDates: {
fromDate: new Date(2020, 10, 28),
toDate: new Date(2020, 10, 30),
},
travelerInfo: [
{ id: 1, dob: new Date(), tripCost: 0, firstName: "", lastName: "" },
],
paymentInfo: {
initialDate: new Date(),
finalDate: null,
},
coverageType: CoverageType.Standard,
tripInfo: {
name: "",
program: "Program Name",
},
contactInfo: {
firstName: "",
lastName: "",
address1: "",
address2: "",
city: "",
state: "",
zip: "",
country: "",
phone: "",
email: "",
},
setQuoteInfo: () => {},
};
const getProperty = <T, K extends keyof T>(obj: T, key: K) => {
return key;
};
const setProperty = <T, K extends keyof T>(obj: T, key: K, value: any) => {
obj[key] = value;
console.log("object is", obj);
};
setProperty(initialQuoteInfo, "country", "United Kingdom");
好的,那我有什么问题?这行得通,但是我对于如何设置比键/值属性更深或更复杂的属性和值感到困惑。例如,如何设置state
fullname
和abbreviation
?假设元素“名称”为“ state.fullname”,我将尝试这样做:
setProperty(initialQuoteInfo, "state.fullName", "Virginia");
TypeScript抱怨:
类型'“ state.fullName”'的参数不可分配给的参数 类型'“ contactInfo” | “国家” | “状态” | “旅行日期” | “ travelerInfo” | “ paymentInfo” | “ coverageType” | “ tripInfo” | “ setQuoteInfo”'。ts(2345)
这有效:
setProperty(initialQuoteInfo, "state", {
fullname: "Virginia",
abbreviation: "VA",
});
我可以通过几种方法来管理此临时任务。一种方法是解析“名称”,如果它有一个点,则进行某种时髦的设置。另一个可能是创建另一个函数,该函数采用已解析的名称,并且与setProperty
函数具有本质上相同的作用。
我忍不住想,也许会有一种更加优雅和实用的方法论,所以我将不胜感激。
答案 0 :(得分:1)
function setProperty(obj: object, key: string, value: any) {
const propertyPath = key.split(".");
const propertyName = propertyPath.pop();
const baseObj = propertyPath.reduce((t: any, c) => t[c], obj);
baseObj[propertyName] = value;
}
经过测试:
setProperty(initialQuoteInfo, "country", "United Kingdom");
setProperty(initialQuoteInfo, "state.fullname", "Virginia");
setProperty(initialQuoteInfo, "coverageType", CoverageType.Standard);
setProperty(initialQuoteInfo, "travelerInfo.0.dob", new Date(1980, 1, 1));
我承认它不符合您的“优雅且实用”的标准,但它确实可以满足您的要求,而且很容易理解。