관리 메뉴

꿈꾸는 개발자

6장 배열 본문

Learning Typescript

6장 배열

rickysin 2023. 3. 6. 21:18
  • TS는 JS와 달리 하나의 배열에 데이터 타입을 하나로 유지한다.
const arr=["a","b"];
arr.push("c");
arr.push(true); //에러 발생 
  • 배열의 타입 유추는 변수 초깃값에서 타입 유추하는 방식과 유사하다.

6.1 배열 타입


  • TS는 변수에 타입 애너테이션을 제공해 배열이 포함해야 하는 값의 타입을 알려준다.
let arr:number[];

arr=[1,2,3,4,5,6];

arr1<number> //와 같은 형식으로도 작성이 가능함! 하지만 개발자들은 위의 방식을 
//더 선호함

6.1.1 배열과 함수 타입


//타입은 string 배열을 반환하는 함수
let createString: ()=>string[];

//타입은 각각의 string을 반환하는 함수 배열 (결국 타입은 배열이란 의미)
let stringCreators:(()=>string)[];
  • 둘을 잘 구별해줘야 한다.

6.1.2 유니언 타입 배열


  • 배열이 여러 선택 타입 중 하나일 때 유니언 타입을 사용함 (유니언 타입에선 괄호가 매우 중요함을 다시 상기해라!)
//타입은 string 또는 number의 배열
let arr1: string | number[];

//타입은 각각 number 또는 string인 요소의 배열
let arr2: (string|number)[];
  • TS는 두 가지 요소 타입이 포함되는 경우 ⇒ 타입 배열임을 인식하게 됨
//타입은 (string | undefined)[] 임!
const arr=[
    "a",
    "b",
    undefined,
]

6.1.3 any 배열의 진화


  • 초기 배열에 타입 애너테이션을 하지 않으면, any[]으로 취급함 ⇒ 값을 할당하면 타입이 변경되지만, any[]이 변경되는 건 좋지 않음(TS의 장점을 살릴 수 없음)
let value=[];

//타입 string[]
value.push("");

//타입: (number|string)[];
value[0]=0;

타입이 계속 변화함 => 좋지 않음!

6.1.4 다차원 배열


  • 2차원 배열 또는 배열의 배열은 두 개의 []를 갖는다!
let value:number[][];
let arr: (number[])[]; //둘 다 같은 표현

value=[
   [1,2], 
   [3,4],
   [5,6], 
]
  • 3차, 4차 등도 동일한 방식으로 타입 애너테이션을 하면 된다.

6.2 배열 멤버


  • TS 전형적인 인덱스 기반 접근 방식을 이해하는 언어
let arr=["a","b"];
//타입 string
const arrs=arr[0];
  • 유니언 타입 배열일 경우 배열의 멤버는 동일한 유니언 타입이다
let arr=["a","b",new Date(1782,6,3)];
//타입 (string | Date)[]
const arrs=arr[0];
  • (의문)왜 &이 아닌 | 을 사용하나?

6.2.1 주의 사항: 불안정한 멤버


  • TS의 타입 시스템은 기술적으로 불안정하다고 알려짐 ⇒ 대부분 올바른 타입을 얻지만 그렇지 않을 경우도 존재 ⇒ 특히 배열은 타입 시스템에서 불안정한 소스
  • 다음 코드는 컴파일러 기본 설정에서 오류를 반환하지 않음
function test(el:string[]){
    console.log(el[90001].length); //타입 오류X
}

test(["hahah","hohoho"]);
  • Cannot read property ‘length’ of undefined가 발생하면 충돌이 발생할 것이란 의미 ⇒ But TS는 검색된 배열의 멤버가 존재하는지 확인하지 않음

6.3 스프레드와 나머지 매개변수


  • TS에서도 JS처럼 스프레드 연산자를 배열에 사용할 수 있음

6.3.1 스프레드


  • 입력된 배열이 동일한 타입이면 출력된 배열도 동일한 타입이다.
  • 서로 다른 타입을 스프레드해 새로운 배열로 합칠 경우 ⇒ 새 배열은 두 개의 원래 타입 중 어느 하나 요소인 유니언 타입 배열로 이해된다!
const a=["a","b","c"]; //타입string
const b=[1,2,3]; //타입 number
const conjoined=[...a,...b];//타입 (string | number)[];

6.3.2 나머지 매개변수 스프레드


  • TS는 나머지 매개변수를 인식할 수 있음 ⇒ 나머지 매개변수를 위한 인수는 나머지 매개변수와 동일한 배열 타입을 가져야 함
function test(a:string,...b:string[]){
    for(const name of b){
        console.log(`${a} ${name}`)
    }
}

const arr1=["a","b","c"];
test("z",...arr1);
const arr2=[1,2,3];
test("z",...arr2); //타입 에러 발생

6.4 튜플


  • JS배열은 이론상 어떤 크기라도 될 수 있음, BUT 튜플이라고 하는 고정된 크기의 배열을 사용하는 것이 유용함
  • 튜플 배열: 각 인덱스 알려진 특정 타입을 가짐 ⇒ 유니언 타입보다 더 구체적!
let arr:[number,string];
arr=[1,"a"];//ok
arr=[false,"a"]//에러 발생!

arr=[1]; //에러 발생 위 튜플이 명시한대로 2개의 요소를 입력 필요!

6.4.1 튜플 할당 가능성


  • 튜플은 가변 길이의 배열보다 더 구체적으로 처리됨 ⇒ (가변 길이의 배열을 튜플 타입에 할당 불가)
let arr1=[true,1]; //타입(number | string)[];

let arr2:[boolean,number]=arr1;//할당 할 수 없음 =>에러 발생
  • 길이가 다른 튜플의 경우도 상호 할당 불가능

나머지 매개변수로서의 튜플

  • 튜플은 구체적인 길이, 타입 정보를 가짐 ⇒ 함수에 전달할 인수를 저장하는데 유용 ⇒ … 나머지 매개변수로 전달된 튜플에 정확한 타입 검사를 제공 가능
function test(a:string,b:number){
    console.log(`${a}, ${b}`);
}

const arr1=["a",1];//타입 (string|number)[];
test(...arr); //에러 발생 둘 다 동일한 타입이거나 타입의 잘못된 순서로 인해 타입의 안전 보장 불가!

const arr2:[string,number]=["a",1];

test(...arr); //ok 만약에 위 튜플 순서가 바뀌면 에러 발생
  • 나머지 매개변수 튜플을 사용하고 싶다면 여러 번 함수 호출하는 인수 목록을 배열에 저장 함께 사용할 수 있음
function trio(name:string, value:[number, boolean]){
    console.log(`${name} ${value[0]} ${value[1]}`);
}

const trios:[string,[number,boolean]][]=[
    ["a",[1,true]], 
    ["b",[2,false]],
    ["c",[3,false]],
]

trios.forEach(el=>trio(...el)); // ok

trios.ForEach(trio) //의 첫 매개변수(string)에 [string, [number,boolean]]자체를 할당하려 하기 때문에 안된다! 

6.4.2 투플 추론


  • TS는 생성된 배열을 튜플이 아닌 가변 길이의 배열로 취급!
    • 변수의 초깃값
    • 함수에 대한 반환값
      • 모두 가변 배열로 취급됨
//반환 타입 (string | number)[]
function test(input:string){
    return [input[0], input.length];
}

//first 타입: string | number;
//size 타입: string | number;
const [first,size]=test("hohoho");
  • 튜플을 나타내는 방법
    • 명시적 튜플 타입
    • const 어서션(assertion)

명시적 튜플 타입


  • 튜플 타입도 타입 애너테이션에 사용할 수 있음 ⇒ 튜플 타입에 반환한다고 선언하고
    • 함수가 튜플 타입을 반환한다고 선언 ⇒ 배열 리터럴을 반환 (튜플로 간주됨)
//반환 타입:[string,number] 튜플을 반환한다고 명시됨
function test(input:string):[string,number]{
    return [input[0],input.length];
}

//firstChar 타입:string
//size 타입:number
const [firstChar,size]=test("asdafsdaf");

const 어서션

  • as const 연산자를 제공함 ⇒ TS 타입을 유츄할 때 읽기 전용(read-only)이 가능한 값 형식을 사용하도록 지시함
//타입 (string | number)[]
const unionArr=[1,"a"];

//타입: readonly[1,"a"];
const readonylTuple=[1,"a"] as const;

readonylTuple[0]=2; //읽기 전용이라 수정 불가!
  • 유연한 배열을 고정된 크기의 튜플로 전환 + 읽기 전용
  • 일기 전용 튜플은 함수 반환에 편리함 (값을 찾는 것을 목적으로 할 때 사용하면 유용!)

Reference:

조시 골드버그, 러닝 타입스크립트, 고승원 옮김, 2023