我想编写一个函数,该函数接受一个对象参数并捕获变量中所有剩余的参数。目的是允许函数接收命名参数(与位置参数相对),其中一些参数是可选的,并在函数中设置默认值。因此,用伪代码是这样的:
interface IMyProps {
a: string
b?: number
}
const myfun1 = (p: {a: string, b?:number, ...rest}) => {
const {a, b = 'hello'} = p;
}
Run Code Online (Sandbox Code Playgroud)
在Typescript 2.0中实现此目标的最佳方法是什么?
更新:
鉴于microsoft/TypeScript#28312的 PR ,您现在可以使用泛型,如下所示:
const myfun1 = <T extends IMyProps>(p: T) => {
const { a, b = 'hello', ...rest } = p;
a; // string
b; // number | 'hello'
rest; // const rest: Pick<T, Exclude<keyof T, "a" | "b">>
}
Run Code Online (Sandbox Code Playgroud)
其中rest变量被推断为 type Omit<T, "a" | "b">,这可能是您想要的。
前 TS4 答案
我认为,如果您已经取消了所有显式命名的属性,则在 TypeScript 中使用 rest 运算符进行的对象解构对应于解构对象类型上的索引签名。这意味着您将有相同的限制,其中其余属性的类型必须至少与所有显式标记属性的并集一样宽。在您的情况下,您可以IMyProps使用这样的索引签名进行扩展:
interface IMyPropsWithIndex {
a: string
b?: number
[k: string]: string | number | undefined
}
Run Code Online (Sandbox Code Playgroud)
因为aisstring的类型和bis的类型number | undefined。您可以向联合添加更多内容,但不能使其更窄,例如string. 如果这对您没问题,那么进行解构的方法将是这样的:
const myfun1 = (p: IMyPropsWithIndex) => {
const { a, b = 'hello' , ...rest } = p;
a; // string
b; // number | 'hello'
rest; // {[k: string]: string | number | undefined}
}
Run Code Online (Sandbox Code Playgroud)
如果你检查变量的类型,你会得到类似上面的内容。
您可以在函数参数中直接使用解构分配:
interface IMyType {
a: number;
b: number;
c: number;
d: number;
[k: string]: number; // use this if you don't know the name of the properties in 'rest'
}
const obj: IMyType = { a: 1, b: 2, c: 3, d: 4 }
// Normal destructuring
const { a, b, ...rest } = obj;
console.log(rest); // {c: 3, d: 4}
// Directly in function arguments
const fn = ({ a, b, ...rest }: IMyType) => { console.log(rest); }
console.log(fn(obj)); // {c: 3, d: 4}
Run Code Online (Sandbox Code Playgroud)