分解函数参数对象和... rest

mar*_*rko 11 typescript

我想编写一个函数,该函数接受一个对象参数并捕获变量中所有剩余的参数。目的是允许函数接收命名参数(与位置参数相对),其中一些参数是可选的,并在函数中设置默认值。因此,用伪代码是这样的:

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中实现此目标的最佳方法是什么?

jca*_*alz 9

更新:

鉴于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)

如果你检查变量的类型,你会得到类似上面的内容。


Playground 链接到代码


klu*_*gjo 8

您可以在函数参数中直接使用解构分配:

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)