为了账号安全,请及时绑定邮箱和手机立即绑定

类型脚本说交集属性不存在

类型脚本说交集属性不存在

qq_花开花谢_0 2022-09-23 16:36:44
我有一个变量,它从一个类型开始,但是在映射了几次之后,应该添加一个属性,就像.但是,在倒数第四行中,打印属性的附加项会给我一个 TS 错误,即使该属性确实存在并且日志记录的工作方式与我预期的一样,打印三个属性 、 和 。IPerson[]_idArray<IPerson & IWithId>_idfnamelname_id我想也许我需要以某种方式重新铸造它,比如mapped = collection.map(mapperB) as Array<IPerson & IWithId>这不起作用,值得庆幸的是,对于imo应该已经根据函数的返回类型获取其类型的变量,这样做似乎非常冗长。mapperBlet _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函数的值,我可以让它工作,即我很好奇为什么我不能使用我的原始变量?const mapped2 = collection.map(mapperB)为什么类型脚本不从显式声明的返回值中推断出 的值?我可以让它为我做这件事吗?mappedmapperB类型脚本游乐场
查看完整描述

3 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

类型脚本从它的第一个赋值(初始化)中推断出的类型,所以它是:mappedIPerson[]


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测试版),我建议阅读这篇文章。


然后,第二个赋值不会扩展定义,但也没有错误,因为对象可以具有其他属性。访问 时,您会收到一个错误,因为 TypeScript 无法从最初推断的类型中确定数组条目还包含属性。_id_id


注意:强制转换 给 TypeScript 没有附加信息,所以结果是一样的。mapped = collection.map(mapperB) as Array<IPerson & IWithId>


为了便于推理类型,我个人建议将转换后的值分配给新变量(如您使用 .并选择富有表现力的变量名称(权衡变得冗长,但如果你保持函数复杂性足够小,这种情况不应该经常发生):const mapped2 = collection.map(mapperB)


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

const filteredListWithIds = filteredList.map(...)

不直接相关,但出现错误:返回新数组。从 的值会立即丢失,因为它映射 = 集合。在基于您的真实代码创建游乐场示例时,也许是一个错误?Array.prototype.map()mappedlet mapped = collection.map(mapperA)s being overwritten at the next line during


查看完整回答
反对 回复 2022-09-23
?
隔江千里

TA贡献1906条经验 获得超10个赞

这里的问题是在以下行:


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

希望这有帮助。


查看完整回答
反对 回复 2022-09-23
?
拉莫斯之舞

TA贡献1820条经验 获得超10个赞

是的,一旦赋值,就无法更改 typescript 中变量的类型。

如上面的示例中所述,您可以使用不同的变量。但是根据你的关注点,你只想使用一个变量,你可以通过一个接一个地链接它们来调用两个映射器。

类型脚本以非常好的方式支持函数调用的链接。因此,您可以将最后两行代码替换为单行代码,如下所示:

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

我希望您觉得这有帮助。您可以解决您的错误。


查看完整回答
反对 回复 2022-09-23
  • 3 回答
  • 0 关注
  • 68 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信