首页 > 解决方案 > 打字稿:'数字| undefined' 不可分配给“number”类型的参数

问题描述

我有一个带有 Activiy 接口和 Mongo Schema 的模型,以及一个接受 ID 并记录它的函数。然后在我的路线中,我查询来自未定义 externalId 的给定客户的所有活动。使用返回的数组,我调用模型中定义的函数,将 externalId 作为参数传递。

但是 TypeScript 一直在抛出:'number | 类型的参数 undefined' 不能分配给“number”类型的参数。类型“未定义”不可分配给类型“数字”。我已经尝试用 if 语句检查 if 来包装调用externalId && typeof externalId === 'number',但我不能让错误消失。

模型:

import { Schema, model, } from 'mongoose';

interface IActivity {
    customer: string,
    externalId?: number,
}

const activitySchema: Schema = new Schema({
    Customer: {
        type: String,
        required: true,
        minlength: 5,
        maxlength: 50,
    },
    externalId: { type: Number, },
});

export function updateExternal(externalId: number): void {
    console.log(externalId);
}

export const Activity = model<IActivityModel>('Activity', activitySchema);

路线:

const completeActivity = await Activity
    .find({
        'externalId': { '$ne': undefined, },
        'customer': 'Foo Customer',
    });

completeActivity.forEach((activity) => {
     updateExternal(activity.externalId); // This is where the error appears
});

标签: node.jstypescript

解决方案


有趣的是,当键可能没有真正的值时,为了获得键的值应该发生什么。activity.externalId有类型number | undefined所以我们该怎么做才能从 tonumber | undefined移动number

我们需要“移除”该类型的那一部分,也就是说,我们需要提供某种方法来将 的所有undefined部分转换number | undefinednumber

通常我们通过提供一些默认值来做到这一点——我们说只要值为undefined,就不要使用它——改用默认值。但是,使用 typescript 很难找到一个好的类型;我们不能指定对象的类型具有我们正在寻找的属性;所以我们必须简单地说它可以是any,因此,该函数只能返回any,如下所示:

interface IX {
    a?: number;
}

function propOr<K extends string | number, U, O extends Record<K, U>>(k: K, defaultValue: U, obj: O) {
    return obj[k];
}

const testFunction1 = (x: IX) => x.a;                // has type number | undefined
const testFunction2 = (x: IX) => propOr('a', -1, x); // type error: 

我们在这里得到的类型错误是:

'IX' 类型的参数不能分配给 'Record<"a", number>' 类型的参数。属性“a”的类型不兼容。输入'号码 | undefined' 不可分配给类型 'number'。类型“未定义”不可分配给类型“数字”。(2345)

我们可能会查看其他库,看看它们做了什么,例如,Sanctuary 有它:

prop(p: string): (q: any) => any;

因此,当键入一个函数时,我们有点卡住了,我们被迫丢失类型信息(除非其他人可以跳出更好的主意)。

我能想到的最好的解决方案是只使用 or 总是得到一个数字:

interface IX {
    a?: number;
}

const a: IX = {};
const b = a.a || 0;

现在b有了类型number


推荐阅读