簡體   English   中英

TypeScript 說不存在交集屬性

[英]TypeScript Says Intersection Property Does Not Exist

我有一個以一種類型開始的變量IPerson[] ,但是在映射了幾次之后,應該添加一個_id屬性,就像Array<IPerson & IWithId>一樣。 但是,在倒數第四行中,打印_id屬性會給我一個 TS 錯誤,即使該屬性確實存在並且日志記錄工作如我所料,打印三個屬性fnamelname_id .

我想也許我需要以某種方式重新投射它,比如

mapped = collection.map(mapperB) as Array<IPerson & IWithId>

這沒有奏效,幸運的是,對於 imo 應該已經根據mapperB function 的返回類型獲取其類型的變量來說,這樣做似乎非常冗長。

let _id = 0;
interface IPerson { 
    fname: string;
    lname: string;
}

interface IWithId { 
    _id: number;
}

function getNumber() { 
    return _id++
}

async function getData(json: string): Promise<IPerson[]> { 
    return JSON.parse(json)
}

function mapperA(entry: IPerson): IPerson { 
    return {
        ...entry,
        lname: entry.lname.toUpperCase()
    }
}
function mapperB(entry: IPerson): IPerson & IWithId { 
    const _id = getNumber();
    return {
        ...entry,
        _id
    } 
}
async function main() {
    const json = `[{"fname":"john","lname":"doe"},{"fname":"jane","lname":"doe"}]`    
    const collection = await getData(json)
    let mapped = collection.map(mapperA)
    mapped = collection.map(mapperB)
    console.log(mapped[0]._id); // Property '_id' does not exist on type 'IPerson'.
    return mapped;
}

main().then(console.log)

如果我使用另一個變量來保存第二個 map function 的值,我可以讓它工作,即const mapped2 = collection.map(mapperB)但我很好奇為什么我不能使用我的原始變量?

為什么 typescript 不從mapperB的明確聲明的返回值推斷mapped的值? 我可以讓它為我做這個嗎?

TypeScript 游樂場

TypeScript 從它的第一個賦值(初始化)推斷mapped的類型,所以它是IPerson[]

In TypeScript, there are several places where type inference is used to provide
type information when there is no explicit type annotation. For example, in this
code

> let x = 3;

The type of the x variable is inferred to be number. This kind of inference takes place
when initializing variables and members, setting parameter default values, and 
determining function return types.

摘自TypeScript 手冊中的“類型推斷”一章(我鏈接了它即將發布的 2.0 測試版),我建議閱讀此內容。

然后第二個賦值不會擴展定義,但也沒有錯誤,因為對象可以具有其他屬性。 當您訪問_id時,您會收到一個錯誤,因為 TypeScript 無法從最初推斷的類型確定數組條目還包含_id屬性。

注意:使用mapped = collection.map(mapperB) as Array<IPerson & IWithId>不會為 TypeScript 提供其他信息,因此結果是相同的。


為了簡化類型的推理,我個人建議將轉換后的值分配給新變量(正如您使用const mapped2 = collection.map(mapperB)提出的那樣。並選擇富有表現力的變量名稱(權衡變得冗長,但這不應該經常發生)如果你保持你的 function 復雜度足夠小):

const filteredList = list.filter(...);
const filteredListWithIds = filteredList.map(...)

不是直接相關,而是一個錯誤: Array.prototype.map() 返回一個數組 let mapped = collection.map(mapperA)中的mapped值立即丟失,因為它在 mapped = collection.map(mapperB)` s being overwritten at the next line during 根據您的真實代碼創建游樂場示例時可能會出錯?

是的,一旦分配了 typescript 中的變量,您就無法更改它的類型。

如上例所述,您可以使用不同的變量。 但是根據您的關注,您只想使用一個變量,您可以通過將它們一個接一個地鏈接來調用兩個映射器。

Typescript 以非常好的方式支持 function 調用的鏈接。 因此,您可以用單行替換最后兩行代碼,如下所示:

let mapped = collection.map(mapperA).map(mapperB)

我希望你覺得這有幫助。 你可以解決你的錯誤。

這里的問題在於以下幾行:

let mapped = collection.map(mapperA) // here you declare mapped with the type IPerson[]
mapped = collection.map(mapperB) // here mapped already has a type and can't be changed
console.log(mapped[0]._id); // here you try to access a property IPerson doesn't have

您可以嘗試按照其他答案鏈接映射器或僅將兩個映射器強制為一個來解決此問題:

function mapper(entry: IPerson): IPerson & IWithId {
    const _id = getNumber();

    return {
        ...entry,
        _id,
        lname: entry.lname.toUpperCase()
    }
}

// later in your main function
let mapped = collection.map(mapper); // here mapped is declared as (IPerson & IWithId)[]
console.log(mapped[0]._id); // now you can access any IWithId property

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM