Typescript:外部库的多余对象属性检查



我正在尝试使用来自外部库的函数notify。

这在库中被声明为

// library.js
export declare const notify: {
(args: NotificationsOptions | string): void;
close(id: unknown): void;
};

现在我想用扩展原始参数的args来调用它。例如,像

// myFile.js
import { notify } from 'library';
const originalArgs = { /* object of type NotificationsOptions */ };
notify(originalArgs); // works
notify({ ...originalArgs, additionalProperty: 'Foo' }); // ts error message "Argument type {..., additionalProperty: string } is not assignable to parameter type NotificationsOptions | string"

到目前为止,这是清楚的,但我想知道解决这个问题的最佳实践。

到目前为止我的想法:

// myFile.js
// 1. typecast with "as" notation:
import { notify } from 'library';
notify({ ...originalArgs, additionalProperty: 'Foo' } as NotificationOptions); // works, but unclean since it's not really of this type?
// 2. disabling inspection with ts-ignore
// works, but unclean?
// 3. disabling inspection by passing in as a predefined const:
import { notify } from 'library';
const extendedArgs = { ...originalArgs, additionalProperty: 'Foo' };
notify(extendedArgs); // works, but unclean, since just doesn't get checked? would say even worse than 2., since it gets only implicitly disabled
// 4. redeclare notify:
import { notify } from 'library';
declare const notify: {
(args: NotificationOptions & { additionalProperty: string}): void;
}; // error "Import declaration conflicts with local eclaration of 'notify'
notify({ ...originalArgs, additionalProperty: 'Foo' });
// 5. don't use import
declare const notify: {
(args: NotificationOptions & { additionalProperty: string}): void;
}; 
notify({ ...originalArgs, additionalProperty: 'Foo' }); // no typescript error, but runtime error "notify is not defined"
// 6. declare extendedNotify
// would probably be my preferred solution, but don't know, how to make it work
import { notify } from 'library';
declare const extendedNotify: {
(args: NotificationOptions & { additionalProperty: string }): void;
};
notify({ ...originalArgs, additionalProperty: 'Foo' }) as extendedNotify; // unresolved type extendedNotify

过度的属性检查更多的是一个提醒您潜在错误的linter功能,而不是一个警告您潜在运行时爆炸的类型安全功能;TypeScript对象类型不是密封的;精确的";(按照microsoft/TypeScript#12936中的要求(,这样您就可以在不违反类型的情况下始终添加属性。

这意味着NotificationsOptions & { additionalProperty: string }可分配给NotificationOptions,因此任何接受NotificationOptions的函数都应该安全地接受NotificationsOptions & { additionalProperty: string }。所有这些都表明notify已经是一个正确类型的函数,但您只希望编译器在传入additionalProperty时不要抱怨过多的属性。


一种方法是将notify分配给一个名为extendedNotify的变量,该变量已用您想要的类型进行了注释:

const extendedNotify: (
args: (NotificationsOptions & { additionalProperty: string })
) => void = notify; // okay

该分配成功是因为notify接受NotificationsOptions,并且它应该安全地接受NotificationsOptions的任何子类型,包括NotificationsOptions & {...}

现在您可以根据需要调用extendedNotify()

extendedNotify({ ...originalArgs, additionalProperty: 'Foo' }); // okay

并且没有多余的属性警告,因为extendedNotify()的参数类型已知该属性。

游乐场链接到代码

最新更新