[TypeScript] Try ...
Tags: typescript
Published: 2021-05-05 22:39:45

## Intro
When I write TypeScript code I sometime use "..."(Three dots).
But because I haven't known so much, so I decided to try using it in some cases.

### Environments
* TypeScript ver.4.2.4

### "..." in JavaScript
I can use "..." for two ways in JavaScript.
They are "Spread syntax" and "Rest parameters".

TypeScript "..." behavior also comes from them.

## Spread syntax
I can copy parameters or array items to other object or array.

```ts
type Print = {
    message: string,
    width: number,
    height: number,
    x: number,
    y: number,
};
type Size = {
    width: number,
    height: number,
};
function start() {
    let sampleSize = {
        width: 1920,
        height: 1080
    };
    const samplePrint = {
        message: 'Hello',
        x: 10,
        y: 50,
        ...sampleSize
    };
    print(samplePrint);
    const array1 = ['Hello', 'World', '!!!'];
    const array2 = [...array1];
    printArray(array2);
}
function print(target: Print) {
    console.log('Print');
    console.log(target);
}
function printArray(targets: readonly string[]) {
    console.log('Print Array');
    console.log(targets);
}
```
#### Result
```
Print
{ message: 'Hello', x: 10, y: 50, width: 1920, height: 1080 }
Print Array
[ 'Hello', 'World', '!!!' ]
```

It copies values and object references(not properties).

```ts
...
type Position = {
    x: number,
    y: number,
};
type Rect = {
    size: Size,
    position: Position
};
function start() {
    let sampleSize = {
        width: 1920,
        height: 1080
    };
    const samplePrint = {
        message: 'Hello',
        x: 10,
        y: 50,
        ...sampleSize
    };
    // samplePrint.width isn't changed
    sampleSize.width = 300;
    print(samplePrint);
...
    const samplePosition: Position = {
        x: 30,
        y: 5
    };
    const sampleRect = {
        size: sampleSize,
        position: samplePosition
    };
    const wrapSample = {
        ...sampleRect
    };
    // wrapSample.size.width is changed to 400
    sampleSize.width = 400;
    printRect(wrapSample);
}
...
```
#### Result
```
Print
{ message: 'Hello', x: 10, y: 50, width: 1920, height: 1080 }
...
printRect
{ size: { width: 400, height: 1080 }, position: { x: 30, y: 5 } }
```

It only copies properties.
```ts
...
class BaseClass {
    public size: Size = {
        width: 10,
        height: 10
    };
    public print() {
        console.log('Hello');
    }
}
class ExtendClass extends BaseClass {
    public position: Position = {
        x: 0,
        y: 50
    };
    public print2() {
        console.log('World');
    }
}
function start() {
...
    const sampleClass = new ExtendClass();
    // this only has "size" and "position".
    // methods aren't copied
    const copiedClass = {
        ...sampleClass
    };
}
...
```

* [Spread syntax (...) - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)
* [JavaScript: The Definitive Guide](https://play.google.com/store/books/details?id=NPbkDwAAQBAJ&pcampaignid=books_web_aboutlink)

## Rest parameters
I can set 0 ~ n arguments for functions or methods.

```ts
...
function start() {
...
    printArgs();
    printArgs('Hello');
    printArgs('Hello', 'World');
}
...
function printArgs(...args: string[])
{
    console.log('printArgs');
    console.log(args);
}
// compile error. rest parameters must be the last argument
function printArgsFailed(...args1: number[], ...args2: string[])
{
    console.log('printArgsFailed');
}
...
```
#### Result
```
...
printArgs
[]
printArgs
[ 'Hello' ]
printArgs
[ 'Hello', 'World' ]
```


I also can separate the parameters.
```ts
...
function start() {
...
    printSeparatedArgs();
    printSeparatedArgs('Hello');
    printSeparatedArgs('Hello', 'World');
    printSeparatedArgs('Hello', 'World', '!!!');
}
...
function printSeparatedArgs(...[a, b]: string[])
{
    console.log('printSeparatedArgs');
    console.log(a);
    console.log(b);
}
...
```
#### Result
```
...
printSeparatedArgs
undefined
undefined
printSeparatedArgs
Hello
undefined
printSeparatedArgs
Hello
World
printSeparatedArgs
Hello
World
```

I also can separate array by rest parameters.

```ts
...
function start() {
...
    printTail();
    printTail('Hello', 'World');
    printTail('Hello', 'World', '!!!');
}
...
function printTail<T extends any[]>(...args: T) {
    const [_, ...result] = args;
    console.log('printTail');
    console.log(result);
}
...
```
#### Result
```
...
printTail
[]
printTail
[ 'World' ]
printTail
[ 'World', '!!!' ]
```
* [Rest parameters - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters)
* [Announcing TypeScript 4.0 | TypeScript](https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/)
* [JavaScript Ellipsis: Three dots ( … ) in JavaScript - DEV Community](https://dev.to/sagar/three-dots---in-javascript-26ci)

## Variadic Tuple Types
From TypeScript 4.0, I can use "..." two or more times for defining Tuple type.

```ts
...
function start() {
...
    const array1 = ['Hello', 'World', '!!!'];
...    
    const nums = [1, 12, 30];
    console.log('Tuple');
    console.log(getTuple(nums, array1));
}
...
function getTuple<T extends number[], U extends string[]>(t: T, u: U): [...T , ...U] {
    return [...t, ...u];
}
...
```
#### Result
```
...
Tuple
[ 1, 12, 30, 'Hello', 'World', '!!!' ]
```

* [Announcing TypeScript 4.0 | TypeScript](https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/)
* [TypeScript 4.0で導入されるVariadic Tuple Typesをさっそく使いこなす - Qiita](https://qiita.com/uhyo/items/7e31bbd93a80ce9cec84)