我們在渲染複雜對象,比如樹組件的樹對象,有嵌套對象/數組結構的時候,js的弱類型讓我們一把梭,幾乎沒遇到什麼問題(只是寫的時候編譯沒問題把。233。。),結合TS後,對樹狀數據的遞歸訪問會是一個問題:
比如數據源的數據聲明爲:
export interface VoiceSkillResponse {
data: {
isExistUpdate: number;
isNewProduct: number;
streamList: {
streamId: string;
streamName: string;
intentList: {
id: number;
intent: string;
isSelect: number;
}[];
}[];
};
}
export interface VoiceSkill {
streamId: string;
streamName: string;
intentList: Array<Intent>;
}
export interface Intent {
id: number;
intent: string;
isSelect: number;
}
我們想根據這樣的數據渲染一個樹組件
function renderNode(dataList: Array<VoiceSkill | Intent>) {
dataList.map((v, k) => {
if (v.intentList) {
return (
<Tree name={v.streamName} key={v.streamName}>
{renderNode(v.intentList)}
</Tree>
);
}
return <Tree name={v.intent} key={v.id} />;
});
}
| 的寫法並不能讓TS自動推導出v的類型和是否有訪問屬性,所以直接在編譯層報錯。
查閱TS文檔:文檔鏈接
我們可知至少兩種解決方法:
as暴力
缺點,寫很多as吧
function renderNode(voiceSkillList: Array<VoiceSkill | Intent>) {
voiceSkillList.map((v, k) => {
if ((v as VoiceSkillList).intentList) {
return (
<Tree name={(v as VoiceSkillList).streamName} key={(v as VoiceSkillList).streamName}>
{renderNode((v as VoiceSkillList).intentList)}
</Tree>
);
}
return <Tree name={(v as IntentList).intent} key={(v as IntentList).id} />;
});
}
寫一個函數類型保護
個人認爲目前最適合的方式?也是官方文檔給的一種方式
function isVoiceSkill(item: VoiceSkill | Intent): item is VoiceSkill {
return (item as VoiceSkill).intentList !== undefined;
}
function renderNode(dataList: Array<VoiceSkill | Intent>) {
dataList.map((v, k) => {
if (isVoiceSkill(v)) {
return (
<Tree name={v.streamName} key={v.streamName}>
{renderNode(v.intentList)}
</Tree>
);
} else {
return <Tree name={v.intent} key={v.id} />;
}
});
}
函數重載
大佬說的一種,但是這樣的話相當於參數在函數裏還是any吧, 失去了類型檢查…?重載主要是在調用的時候做類型檢查用的,存疑。。。
function renderNode(dataList: VoiceSkill[]): Array<React.ReactElement<any>>;
function renderNode(dataList: Intent[]): Array<React.ReactElement<any>>;
function renderNode(dataList: any[]): Array<React.ReactElement<any>> {
return dataList.map((v, k) => {
if (v.intentList) {
return (
<Tree name={v.streamName} key={v.streamName}>
{renderNode(v.intentList)}
</Tree>
);
}
return <Tree name={v.intent} key={v.id} />;
});
}