running TSC: part2

the Other Object·2023년 4월 12일
0

ch5. 함수
ch6. 배열
ch7. 인터페이스
ch8. 클래스
ch9. 타입제한자
ch10. 제네릭

ch5. 함수

  • 한쪽 끝에는 함수 인수가 있고, 다른쪽 끝에는 반환 타입이 있다.
  • 함수 매개변수와 반환타입에서 동일한 작업을 수행하는 방법과 이 방법이 유용한 이유???

함수 매개변수

//1.
const sing = (song) => {
  console.log('Singing: ${song}!');
};
	- sing함수는 song매개변수를 받아 콘솔에 출력한다.
    - sing함수를 작성한 개발자가 song 매개변수를 제공하기 위해 의도한 값의 타입은 무엇?
    - string인가? 재정의된 toString() 메서드가 있는 객체인가? 이 코드는 버그인가???
    - 명시적 타입 정보가 선언되지 않으면 절대 타입을 알 수 없다.
    - 타입스크립트가 이를 any타입으로 간주하며 매개변수의 타입은 무엇이든 될 수 있다.
 

//2.
const sing = (song: string) => {
  console.log('Singing: ${song}!');
};
	- 변수와 마찬가지로 타입스크립트를 사용하면 타입 애너테이션으로 함수 매개변수의 타입을 선언할 수 있다.
    - 코드를 유효한 타입스크립트 구문으로 만들기 위해 함수 매개변수에 적절한 타입애너테이션을 추가할 필요는 없다.
    - 타입스크립트는 타입 오류로 오류를 계속 알리지만, 이미 시작 된 자바스크립트는 계속 실행 됨.
    - song 매개변수에 타입 선언이 누락된 코드 스니펫은 여전히 타입스크립트에서 자바스크립트로 변환 된다. 

필수 매개변수

  • 자바스크립트에서는 인수의 수와 상관없이 함수를 호출할 수 있다.
  • 하지만 타입스크립트는 함수에 선언 된 모든 매개변수가 필수라고 가정한다.
  • 함수가 잘못된 수의 인수로 호출되면, 타입스크립트는 타입오류의 형태로 이의를 제기함.
  • 함수가 너무 적꺼나 많은 인수로 호출되면 타입스크립트는 인수의 개수를 계산한다.
//1.
const singTwo = (first: string, second: string) => {
  console.log('${first} / ${second}');
};

singTwo("Ball and Chain");
// log: "Ball and Chain / undefined"
// Error: Expected 2 arguments, but got 1.
singTwo("I will Servive", "Higher Love");
// log: "I will Servive", "Higher Love"
singTwo("Go your own way", "The Chain", "Dreams");
// log: "Go your own way / The Chain"
// Error: Expected 2 arguments, but got 3.
	- 함수에 필수 매개변수 required Parameter를 제공하도록 강제하면, 예상되는 모든 이수값을 함수 내에 존재하도록 만들어 타입안정성을 강화하는데 도움이 된다.
    - 모든 인수값이 존재하는지 확인하지 못하면 이전 singTwo함수가 undefined 를 로그로 남기거나 인수를 무시하는 것과 같이 코드에서 예기치 않은 동작이 발생한다.
    - 매개변수는 인수로 받을 것으로 예상되는 함수의 선언을 나타낸다. 
    - 인수는 함수를 호출할 때 매개변수에 제공되는 값을 나타낸다.

const singTwo = (first: string, second: string) => {
  				// first와 second : 매개변수
  console.log('${first} / ${second}');
};
singTwo("Go your own way", "The Chain", "Dreams");
									 // "Dreams"와 같은 문자열은 : 인수

선택적매개변수

  • 자바스크립트에서 함수 매개변수가 제공되지 않으면 함수 내부의 인수값은 undefinde으로 기본값이 설정된다.
  • 함수 매개변수는 제공할 필요가 없을 때도 잇고, undefined값을 위해 의도적으로 사용할 수도 있다.
  • 타입스크립트가 이러한 선택적 매개변수에 인수를 제공하지 못하는 경우, 타입 오류를 보고하지 않도록/
  • 타입스크립트에서는 : 선택적 객체타입 속성과 유사하게 타입애너테이션의 : 앞에 ? 를 추가해 매개변수가 선택적이라고 표시한다.
  • 함수 호출에 선택적 매개변수를 제공할 필요는 없다.
  • 선택적 매개변수에는 항상 | undefined 가 유니언타입으로 추가되어 있음/
//1.
const announceSong = (song: string, singer?: string) => {
  console.log('Song: ${song}');
  if (singer) {
    console.log('Song: ${song}')
  }
};
announceSong('Greensleeves');
announceSong('Greensleeves', undefined);
announceSong('Chandelier', 'Sia');
	- announceSong함수에서 singer매개변수는 선택사항으로 표시된다.
    - 타입은, string | undefined 이며 함수 호출자가 singer 매개변수를 위한 인수를 제공할 필요가 없다.
    - 만일, singer가 제공되면 string 값이거나 undefined일 수 있다.
    - 이러한 선택적 매개변수는 항상 암묵적으로 undefined 가 될 수 있음.
    - singer는 string | undefined 타입으로 시작한 후 if 문에 따라 string타입으로 좁혀짐.
    - 선택적 매개변수는, | undefined 를 포함하는 유니언 타입 매개변수와는 다름.
    - ? 으로 표시된 선택적 매개변수가 아닌 매개변수가 아닌 매개변수는 값이 명시적으로 undefined 라도 항상 제공되어야 함.
    
    
//2.
const announceSongBy = (song: string, singer: string|undefined) => {
  /* ... */
};
announceSongBy('Greensleeves');
// Error: Expected 2 arguments, but got 1.
announceSongBy('Greensleeves', undefined);
announceSong('Chandelier', 'Sia');
	- announceSongBy 함수의 singer 매개변수는 명시적으로 제공되어야 한다.
    - singer는 string 값이거나 undefined가 될 수 있다.
    - 함수에서 사용되는 모든 선택적 매개변수는 마지막 매개변수여야 한다.
    - `필수 매개변수 전에 선택적 매개변수를` 위치시키면 타입스ㅡ구문오류 발생
    	const announceSinger = (singer?: string, song: string) => {};
		// Error: A required parameter cannot follow an optional parameter

기본매개변수

  • 자바스크립트에서 선택적 매개변수를 선언할 때 =와 값이포함된 기본값을 제공할 수 있다.
  • 즉, 선택적 매개변수에는 기본적으로 값이 제공되기 때문에 해당 타입스ㅡ타입에는 암묵적으로 함수내부에 |undefined 유니언타입이 추가된다.
  • 타입스ㅡ는 함수의 매개변수에 대해 인수를 누락하거나 undefined 인수를 사용해서 호출하는 것을 여전히 허용함.
  • 타입스ㅡ의 타입추론은 초기 변수값과 마찬가지로 기본 함수 매개변수에 대해서도 유사하게 작동한다.
  • 매개변수에 기본값이 있고 타입 애너테이션이 없는 경우, 타입스ㅡ는 해당 기본값을 기반으로 매개변수 타입을 유추함.
//1.
const rateSong = (song: string, rating = 0) => {
  console.log('${song} gets ${rating}/5 stars!');
}
rateSong('Photograph');
rateSong('Set Fire to the Rain', 5);
rateSong('Set Fire to the Rain', undefined);
rateSong('At Last!', "100");
// Error: Argument of type '"100"' is mot assignable to paraeter of type 'number | undefined'
	- rateSong 함수에서 rating은 number 타입으로 유추되지만, 함수를 호출하는 코드에서는 선택적 number | undefined 가 된다.

나머지매개변수

  • 자바스킙트의 일부 함수는 임의의 수의 인수로 호출할 수 있도록 만들어진다.
  • ...스프레드연산자는 함수 선언의 마지막 매개변수에 위치하고, 해당 매개변수에서 시작해 함수에 전달 된 '나머지'인수가 모두 단일 배열에 저장되어야 함을 나타낸다.
  • 타입스ㅡ는 이러한 나머지 매개변수의 타입을 일반 매개변수와 유사하게 선언가능.
  • 단, 인수배열 나타내기위해 끝에 [] 구문이 추가된다는 것.
//1.
const singAllTheSongs = (singer: string, ...songs: string[]) => {
  for (const song of songs) {
    console.log('${song}, by ${singer}')
  }
};
singAllTheSongs('Alicia Keys');
singAllTheSongs('lady gaga', 'just Dance', 'poker face');
singAllTheSongs('Ella Fitzgerald', 2000);
// Error: Argument of type 'number' is not assignable to parameter of type 'string';
	- singAllTheSongs 은 songs 나머지 매개변수에 대해 0개 이상의 string 타입 인수를 사용할 수 있다.

반환타입

  • 타입스크립트는 지각적perceptive이다.
  • 함수가 반환할 수 있는 가능한 모든 값을 이해하면 함수가 반환하는 타입을 알 수 있다.
  • singSongs는 타입스크립트에서 number를 반환함
//1.
//타입: (song: string[]) => number
const singSongs = (songs: string[]) => {
  for (const song of songs) {
    console.log('${song}');
  }
  return (
    songs.length;
  )
}
	- 함수에 다른 값을 가진 여러개의 반환문을 포함하고 있다면, 타입스크립트는 반환타입을 가능한 모든 반환타입의 조합으로 유추한다.
    
    
    
//2.
//타입: (songs: string[], index: number) => string | undefined
const getSongAt = (songsL string[], index: number) => {
  return (
    index < songs.length ? songs[index] : undefined;
  )
}
	- getSongAt 함수는 string | undefined를 반환하는 것으로 유추 된다.
    - 두가지 가능한 반환값이 각각 string 과 undefined 이기 때문.

명시적반환타입

  • 변수와 마찬가지로 타입애너테이션을 사용해 함수의 반환 타입을 명시적으로 선언하지 않는 것이 좋다. 그러나 특히 함수에서 반환 타입을 명시적으로 선언하는 방식이 매우 유용할 때가 종종 있음.
    - 가능한 반환값이 많은 함수가 항상 동일한 타입의 값을 반환하도록 강제한다.
    • 타입스크립트는 재귀함수의 반환타입을 통해 타입을 유추하는 것을 거부한다.
    • 수백개 이상의 타입스크립트 파일이 있는 매우 큰 프로젝트에서 타입스크립트 타입검사ㅏ 속도를 높일 수 있다.
//1.
const singSongRecursive = (songs: string[], count = 0): number => {
  return (
    songs.length ? singSongsRecursive(songs.slice(1), count+1) : count;
  )
};
	- 함수의 반환문이 함수의 반환 타입으로 할당할 수없는 값을 반환하는 경ㅇ 타입스크립트는 할당 가능성 오류를 표시함.

    
//2.
const getSongRecordingDate = (song: string): Date | undefined => {
  switch (song) {
    case "Strange Fruit":
      return new Date('April 20, 1939');
    case "GreensLeeves";
      return "unknown";
      // Error: Type 'string' is not assignable to type 'Date'
    default:
      return undefined;
  }
};
	- getSongRecordingDate함수는 Date | undefined를 반환하도록 명시적으로 선언했는데,
    - 반환문 중 하나가 string을 반환하도록 잘못 제공하고 있다.

함수타입

  • 자바스크립트에서는 함수를 값으로 전달할 수 있다.
  • 즉, 함수를 가지기 위한 매개변수 또는 변수의 타입을 선언하는 방법이 필요하다.
  • 함수타입 구문은 화살표함수와 유사하지만 함수 본문 대신 타입이 있다.
//1. 
const nothingInGivesString: () => string;
	- nothingInGivesString변수타입은 매개변수가 없고 string타입을 반환하는 함수이다.
 
//2.
const inputAndOutput: (songs: string[], count?: number) => number;
	- inputAndOutput변수타입은, string[]매개변수와 count선택적매개변수 및 number값을 반환하는 함수.
    
* 함수타입은 콜백 매개변수(함수로 호출되는 매개변수)를 설명하는데에 자주 사용된다.
//3.
const songs = ['juice', 'shake it off', 'whatup'];
const runOnSongs = (getSongAt: (index: number) => string) => {
  for (let i=0; i<songs.length; i+=1) {
    console.log(getSongAt(i))
  }
}
const getSongAt = (index: number) => {
  return (
    '${songs[index]}'
  );
};
runOnSongs(getSongAt);
const logSong = (song: string) => {
  return (
    '${song}'
  );
};
runOnSongs(logSong);
// 1. Error: Argument of type '(song: string) => string' is not assignable to parameter of type '(index: number) => string'. 
// 2.	Types of parameters 'song' and 'index' are incompatible.
// 3.	Type 'number' is not assignable to type 'string'.
	- runOnSongs(logSong)에 대한 오류메시지는 할당 가능성 오류의 예로 몇가지 상세한 단계까지 제공.
    - 두 함수를 서로 할당할 수 없다는 오류를 출력할 때 타입스크립트는 일반적으로 3가지 단계제공
    	1. 두 함수 타입을 출력한다.
        2. 일치하지 않는 부분을 지정한다.
        3. 일치하지 않는 부분에 대한 정확한 할당가능성오류를 출력
    - 오류
		1. longSongs: (song: string) => string 은 getSongAt: (index: number) => string 에 할당되도록 제공된 타입이다.
        2. longSong의 song 매개변수는, getSongAt의 index 매개변수로 할당된다.
        3. song의 string 타입은 index의 number타입에 할당할 수 없다.
    - 타입스크립트에서 여러줄로 나타나는 오류가 어려워보일 수 있지만 한줄 한줄씩 읽으며 각 부분이 전달하는 내용을 이해하자.
    

함수타입 괄호

  • 함수타입은 다른 타입이 사용되는 모든 곳에 배치할 수 있ㄷ.
  • 여기에는 유니언 타입도 포함된다.
  • 유니언타입의 애너테이션에서 함수 반환 위치를 나타내거나 유니언타입을 감싸는 부분을 표시할 때 괄호를 사용.
//타입: string | undefined 유니언을 반환하는 함수
const returnsStringOrUndefined = () => string | undefined;

//타입: undefined 또는 string을 반환하는 함수
const mayneReturnsString: (() => string) | undefined;

매개변수 타입 추론

  • 매개변수로 사용되는 인라인함수를 포함하여 작성한 모든 함수에 대해 매개변수를 선언해야한다면 번거로움
  • 다행히도, 타입스크립트는 선언된 타입의 위치에 제공된 함수의 매개변수 타입을 유추가능하다.
//1.
const singer: (song: string) => string;
singer = function (song) {
  // song: string타입
  return 'Singing: ${song.toUpperCase()}!';
};
	- singer변수는 string타입의 매개변수를 갖는 함수로 알려져 있으므로
    - 나중에 singer가 할당되는 함수 내의 song 매개변수는 string일것이다 는 것을 알 수 있다.

//2.
const songs = ['Call Mee', 'Jolene', 'The Chain'];
songs.forEach((song, index) => {
  console.log('${song} is at ${index}')
  // song: string, index: number
})
	- song과 index매개변수는 타입스크립트에 따라 각각 string과 number로 유추된다.

함수타입별칭

  • '유니언과 리터럴'에서 다룬 타입별칭
  • 함수타입에서도 동일하게 타입별칭 사용가능
//1.
type StringToNumber = (input: string) => number;
const stringToNumber: StringToNumber;
stringToNumber = (input) => input.length;
stringToNumber = (input) => input.toUpperCase();
// Error: Type 'string' is not assignable to type 'number'.
	- StringToNumber타입은 string타입을 받고 number타입을 반환하는 함수의 별칭을 지정한다. 별칭은 이후 변수타입을 설명하는데 사용함.
    - 비슷하게 함수매개변수도 함수타입을 참조하는 별칭입력가능.
    
//2.
type NumberToString = (input: number) => string;
const useNumberToString = (numberToString: NumberToString) => {
  console.log('The string id: ${numberToString(1234)});
};
usesNumberToString((input) => '${}! Hooray!');
usesNumberToString((input) => input+2);
//Error: Type 'number' is not assignable to type 'string';
	- useNumberToString함수는 함수타입 별칭인 NumberToString의 단일 매개변수를 가진다.
    - 타입별칭은 특히 함수타입에 유용함.
    - 타입별칭을 이용하면 반복적으로 작성하는 매개변수와 반환타입을 갖는 코드공간을 많이 절약할 수 있다.
    

void 타입

  • 일부함수는 어떤 값도 반환하지 않는다.
  • 예를들면, return문이 없는 함수이거나 값을 반환하지 않는 return문을 가진 함수의 경웅미.
  • 타입스크립트는 void키워드를 사용해 반환값이 없는 함수의 반환타입을 확인할 수 있다.
//1.
const lonSong = (song: string | undefined): void => {
  if (!song) {
    return;
  }
  console.log('${song}');
  return true;
  // Error: Type 'boolean' is not assignable to type 'void';
};
	- 반환타입이 void 인 함수는 값을 반환하지 않을 수 있다.
    - logSong 함수는 void를 반환하도록 선언되었으므로 값 반환을 허용하지 않음.
    - 함수타입 선언시 void반환타입은 매우 유용하다.

    
//2.
const songLogger:(song:string) => void;
songLogger = (song) => {
  console.log('${songs}');
};
songLogger('Heart of Glass');
    - 함수타입 선언할 때 void를 사용하면 함수에서 반환되는 모든 값은 무시된다.
	- songLogger 변수는 song: string을 받고, 값을 반환하지 않는 함수이다.
    
//3.
const returnsVoid = () => {
  return;
};
const lazyValue: string | undefined;
lazyValue = returnsVoid();
//Error: Type 'void' is not assingnable to type 'string|undefined'
	- 자바스크립트함수는 실제값이 반환되지 않으면 기본으로 모두 undefined 를 반환하지만, voidundefined와 다르다.
    - void는 함수의 반환 타입이 무시된다는 것을 의미하고, undefined 는 반환되는 리터럴값 이다. 
    - undefined 를 포함하는 대신 void타입의 값을 할당하려고 하면 타입오류 나타남.
    
//4.
const records: string[] = [];
const saveRecords = (newRecords: string[]) => {
  newRecords.forEach(record => records.push(record));
}
saveRecords(['21', 'Come On Over', 'The Bodyguard'])
	- undefinedvoid 를 구분해서 사용하면 매우 유용하다.
    - 특히, void를 반환하도록 선언 된 타입 위치에 전달된 함수가 반환 된 모든 값을 무시하도록 설정할 떄 유용하다.
    - 예를들어, 배열의 내장 forEach 메서드는 void를 반환하는 콜백을 받는다.
    - forEach에 제공되는 함수는 원하는 모든 값을 반환할 수 있다.
    - saveRecords 함수의 records.push(record)number(배열의 .push()에서 반환된 값)를 반환하지만, 여전히 newRecords.forEach 에 전달 된 화살표함수에 대한 반환값이 허용된다.
    - void 타입은 자바스크립트가 아닌 함수의 반환 타입을 선언하는데 사용하는 타입스크립트 키워드.
    - void 타입은 함수의 반환값이 자체적으로 반환 될 수 있는 값도 아니고, 사용하기 위한 것도 아님.

never반환타입

  • 일부함수는 값을 반환하지 않을 뿐만 아니라 반환할 생각도 전혀 없음.
  • never반환 함수는 (의도적으로) 항상 오류를 발생시키거나 무한 루프를 실행하는 함수이다.
  • 함수가 절대 반환하지 않도록 의도하려면 명시적:never타입 애너테이션을 추가해 해당 함수를 호출한 후 모든 코드가 실행되지 않음.
const fail = (message: string): never => {
  throw new Error('Invariant failure: ${message}.');
};
const workWithUnsafeParam = (param: unknown) => {
  if (typeof param !== 'string') {
    fail('param should be a string, not ${typeof param}')
  }
  param.toUpperCase();
};
	- 함수가 절대 반환하지 않도록 의도하려면 명시적 : never 타입 애너테이션을 추가해 해당 함수를 호출한 후 모든 코드가 실행 되지 않음을 나타낸다.
	- fail함수는 오류만 발생시키므로 param의 타입을 string으로 좁혀서 타입스크립트의 제어흐름분석을 도와준다.
    - never는 void와는 다름.
    - void는 아무것도 반환하지 않는 함수를 위한 것이고,
    - never는 절대 반환하지 않는 함수를 위한 것.

함수오버로드

  • 일부 자바스크립트 함수는 선택적매개변수와 나머지 매개변수만으로 표현할 수 없는 매우 다른 매개변수들로 호출 될 수 있다.
  • 이러한 함수를 오버로드 시그니처 overload signature라고 불리는 타입스크립트 구문으로 설명할 수 있다.
  • 즉, 하나의 최종 구현 시그니처와 그 함수의 본문 앞에 서로 다른 버전의 함수이름, 매개변수, 반환타입을 여러번 선언한다.
  • 오버로드 된 함수호출에 대해 구문오류를 생성할지 여부를 결정할 때 타입스크립트는 함수의 오버로드 시그니처만 확인한다.
  • 구현시그니처는 함수의 내부 로직에서만 사용된다.
//1.
function createDate(timestamp: number): Date;
function createDate(month: number, day: number, year: number): Date;
const createDate = (monthOrTimestamp: number, day?: number, year?: number) => {
  return (
    day === undefined || year === undefined 
    ? new Date(monthOrTimestamp) 
    : new Date(year, monthOrTimestamp, day)
  );
};
createDate(554356800);
createDate(7, 27, 1987);
createDate(4, 1);
// Error: No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments
	- createDate 함수는 1개의 timestamp 매개변수 또는 3개의 매개변수(month, day, year)를 사용해 호출.
    - 허용된 수의 인수를 사용해 호출할 수 있지만 2개의 인수를 사용해 호출하면 2개의 인수를 허용하는 오버로드 시그니처가 없기 때문에 타입오류 발생한다.
    - 함수오버로드는 복잡하고 설명하기 어려운 함수타입에 사용하는 최후의 수단. 함수를 단순하게 유지하고 가능하면 함수 오버로드를 사용하지 않는 것이 좋음.

ch6.배열

유연한 배열과 고정된 튜플

//1.
const elements = [true, null, undefined, 42];
elements.push('even', ['more']);
//elements배열의 값: [true, null, undefined, 42, 'even', ['more']]
	- 자바스크립트 배열은 매우 유연하고 내부에 모든 타입의 값을 혼합해서 저장할 수 있다.
    - 대부분의 개별 자바스크립트 배열은 하나의 특정 타입의 값만 가진다.
    - 다른 타입의 값을 추가하게 되면 배열을 읽을 때 혼란을 줄 수 있다.
    - 타입스크립트는 초기배열에 어떤 데이터 타입이 있는지 기억하고, 배열이 해당 데이터타입에서만 작동하도록 제한한다.

//2.
const warriors = ['Artemisia', 'Boudica'];
warriors.push('Zenobia');
warriors.push(true);
//Error: Argument of type 'boolean' is not assignable to parameter of type 'string'.
	- warriors배열이 초기에 string타입의 값을 포함한다는 것을 알고 있으므로 이후 string 타입의 값 추가는 허용하지만 다른 데이터타입 추가는 허용하지 않는다.
    - 타입스크립트가 초기배열에 담긴 요소를 통해 배열의 타입을 유추하는 방법은 변수의 초기값에서 변수타입을 유추하는 방법과 유사함.
    - 타입스크립트는 값이 할당되는 방식에서 코드의 의도 된 타입을 이해ㅏㅎ려고 시도하며 배열도 그렇다.
    

배열타입

  • 다른 변수선언과 마찬가지로 배열을 저장하기 위한 변수는 초기값이 필요하지 않음.
  • 변수는 undefined로 시작해서 나중에 배열값을 받을 수 있다.
  • 타입스크립트는 변수에 타입 애너테이션을 제공해 배열이 포함해야 하는 값의 타입을 알려주려고 함.
  • 배열에 대한 타입애너테이션은 배열의 요소타입 다음에 [] 가 와야함.
//1.
const arrayOfNumbers: number[];
arrayOfNumbers = [4.8,45,46,23,12];
	- 배열 타입은 Array<number> 같은 구문으로도 작성할 수 있다. 하지만 대부분은 더 간단한 number[]를 선호.

배열과 함수타입

  • 배열타입은 함수타입에 무엇이 있는지를 구별하는 괄호가 필요한 구문 컨테이너의 예이다.
  • 괄호는 애너테이션의 어느부분이 함수반환부분이고 어느부분이 배열타입 묶음인지를 나타내기 위해 사용.
const createStrings: () => string[];
//타입은 string배열을 반환하는 함수

const stringCreators: (() => string)[];
//타입은 각각의 string을 반환하는 함수배열
	- 함수타입인 createStrings, 배열타입인 stringCreator 와 동일하지 않다.

유니언타입배열

  • 배열의 각 요소가 여러 선택 타입 중 하나일 수 있음을 나타내려면 유니언타입을 사용한다.
  • 유니언 타입으로 배열타입을 사용할 떄 애너테이션의 어느 부분이 배열의 콘텐츠이고 어느 부분이 유니언 타입 묶음인지를 나타내기 위해 괄호를 사용해야 할 수도 있다.
  • 유니언타입배열에서 괄호사용은 매우 중요함.
//1.
* 두 타입은 동일하지 않다.
const stringOrArrayOfNumbers: string | number[];
//타입은 string 또는 number의 배열

const arrayOfStringOrNumbers: (stirng | number)[];
//타입은 각각 number 또는 string인 요소의 배열
	- 타입스크립트는 배열의 선언에서 두가지 이상의 요소타입이 포함 되는 경우, 유니언타입 배열임을 알게 된다.
    -, 배열의 요소타입은 배열에 담긴 요소에 대한 모든 가능한 타입의 집합.
    
    
//2.
    //타입: (stirng | undefined)[]
const namesMaybe = [
  'Aqualtune',
  'Blenda',
  undefined
];
	- namesMayne는 string값과 undefined 값을 모두 가지므로 (string | undefined)[] 타입이다.

any배열의 진화

  • 초기에 빈 배열로 설정된 변수에서 타입애너테이션을 포함하지 않으면 타입스크립트는 배열을 any[]로 취급하고 모든 콘텐츠를 받을 수 있다.
  • 하지만 any변수가 변경되는 것처럼, any[]배열이 변경되는 것도 좋아하지 않음.
  • 타입애너테이션이 없는 빈 배열은 잠재적으로 잘못된 값 추가를 허용해 타입스크립트의 타입검사기가 갖는 이점을 부분적으로 무력화함.
//1.
//타입: any[]
const values = [];

//타입: string[]
values.push('');

//타입: (number | string)[]
values[0] = 0;
	- values배열은 any요소를 갖고 시작해 string요소를 포함하도록 바뀐 다음, 다시 number|string 요소로 바뀐다.
    - 변수와 마찬가지로 배열이 any타입이 되도록 허용하거나 일반적으로 any타입을 사용하도록 허용하면 타입스크립트의 타입검사목적을 부분적으로 무효화함. 타입스크립트는 값의 타입을 알 떄 가장 잘 작동한다.
    

다차원배열

  • 2차원배열 또는 배열의 배열은 두개의 []대괄호를 가진다.
//1.
const arrayOfArrayOfNumbers: number[][];
arrayOfArrayOfNumbers = [
  [1,2,3],
  [2,4,6],
  [3,5,7]
];
	- 3차원배열 또는 배열의 배열의 배열에는 세개의 []가 있고
    - 4차원배열에는 네개의 [] 5차원에는 ...
    - 다차원배열타입은 새로운개념이 아님
    - 2차원 배열은 원래의 타입을 가지며 끝에 []가 있고, 그 뒤에 []을 추가하는 것.
    
//2.
const arrayOfArrayOfNumbers: (number[])[];
	- arrayOfArraysOfNumbers배열은 number[][]타입이고 (number[])[]으로 나타낼 수 있다.

배열멤버

  • 타입스크립트는 배열의 멤버를 찾아서 해당 배열의 타입요소를 되돌려주는 전형적인 인덱스 기반 접근방식을 이해하는 것이다.
//1.
const defenders = ['Clarenza', 'Dina'];

//타입: string
const defender = defenders[0];
	- defenders배열은 string[]타입이므로 defender는 string타입이다.
    - 유니언타입으로 된 배열의 멤버는 그 자체로 동일한 유니언타입이다.
    
//2.
const solidersOrDates = ['Deborah Sampson', new Date(1782, 6, 3)];

//타입: string | Date
const solidersOrDate = solidersOrDates[0];
- solidersOrDates는 (string | Date)[]타입이므로 solidersOrDate 변수는 string | Date 타입이다.

주의사항: 불안정한 멤버

  • 타입스크립트 타입시스템은 기술적으로 불안정하다고 알려져 있음. 특히, 배열은 타입시스템에서 불안정한 소스이다.
  • 기본적으로 타입스크립트는 모든 배열의 멤버에 대한 접근이 해당 배열의 멤버를 반환한다고 가정하지만, 자바스크립트에서조차도 배열으 ㅣ길이보다 큰 인덱스로 배열요소에 접근하면 undefined를 제공
//1.
const withElements = (elements: string[]) => {
  console.log(elements[9001].length);
  //타입오류없음
};
withElements(["It's", "over"]);
	- 런타입 시 Cannot read property 'length' of undefined 가 발생하며 충돌할거라고 유추할 수 있지만, 타입스크립트는 검색된 배열의 멤버가 존재하는지 의도적으로 확인하지 않는다.
    - elements[9001]undefined 가 아니라 string 타입으로 간주된다.
    - 타입스크립트에는 배열조회를 더 제한하고 타입을 안전하게 만드는 noUncheckedIndexedAccess 플래그가 있지만, 이 플래그는 매우 엄격해서 사용 잘 하지않음.

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

  • ...연산자를 사용하는 나머지 매개변수와 배열 스프레드는 자바스크립트에서 배열과 상호작용하는 핵심방법.

스프레드

  • ...스프레드spread연산자를 사용해 배열을 결합한다.
  • 타입스크립트는 입력된 배열 중 하나의 값이 결과배열에 포함될 것임.
  • 만약에, 입력된 배열이 동일한 타입이라면 출력 배열도 동일한 타입이다.
  • 서로 다른 타입의 두 배열을 함꼐 스프레드해 새 배열을 생성하면 새 배열은 두개의 원래 타입 중 어느 하나의 요소인 유니언타입 배열로 이해됨.
//1.
//타입: string[]
const soldiers = ['harriet', 'joan', 'khutulun'];
//타입: number[]
const soldierAges = [90, 19, 45];
//타입: (string | number)[]
const conjoined = [...soldiers, ...soldierAges];
	- conjoined 배열은 string타입과 number타입 값을 모두 포함하므로 
    

나머지 매개변수 스프레드

  • 타입스크립트는 나머지 매개변수로 배열을 스프레드하는 자바스크립트 실행을 인식하고 이에 대해 타입검사를 수행한다.
  • 나머지 매개변수를 위한 인수로 사용되는 배열은 나머지매개변수와 동일한 배열 타입을 가져야 한다.
const logWarriors = (greeting: string, ...names: string[]) => {
  for (const name of names) {
    console.log('${greeting}, ${name}!')
  }
}
const warriors = ['Cathay Williams', 'Lozen', 'Nzinga']
logWorriors('Hello', ...worriors);
const birthYears = [1844, 1840, 1583];
logWarriors('Born in', ...birthYears);
//Error: Argument of type 'number' is not assignable to parameter of type 'string'.
	- logWarriors함수는 ...names 나머지 매개변수로 string 값만 받는다.
    - string[]타입배열을 스프레드하는 것은 허용되지만 number[]는 허용되지 않음.
    

튜플

  • 자바스크립트 배열은 이론 상 어떤 크기라도 될 수 있지만
  • 때로는 고정된 크기의 배열인 튜플tuple을 사용하는 것이 유용하다.
  • 튜플 배열은 각 인덱스에 알려진 특정 타입을 가지며 배열의 모든 가능한 멤버를 갖는 유니언 타입보다 더 구체적임.
  • 튜플타입을 선언하는 구문은 배열 리터럴처럼 보이지만 요소의 값 대신 타입을 적음.
//1.
const yearAndWarrior: [number, string];
yearAndWarrior = [530, 'Tomyris'];
yearAndWarrior = [false, 'Tomyris'];
//Error: Type 'boolean' is not assignable to type 'number'.
yearAndWarrior = [530];
//Error: Type '[number]' is not assignable to type '[number, string]'.
//	Source has 1 element(s) but target requires 2.
	- yearAndWarrior배열은 인덱스 0에 number타입 값을 갖고, 인덱스 1에 string값을 갖는 튜플타입으로 선언됨.
    - 자바스크립트에서는 단일 조건을 기반으로 두개의 변수에 초기값을 설정하는 것처럼 한번에 여러 값을 할당하기 위해 튜플과 배열구조분해할당array destructuring을 함께 자주 사용한다.
    
//2.
// year 타입 : number
// warrior 타입 : string
const [year, warrior] = Math.random() > 0.5 ? [340, 'Archidamia'] : [1828, 'Rani or Jhansi']
	- 타입스크립트는 위 코드에서 year은 항상 number이고, warrior는 항상 string임을 인식한다.

튜플할당가능성

  • 타입스크립트에서 튜플타입은 가변길이variableLength의 배열 타입보다 더 구체적으로 처리됨.
  • 즉, 가변길이의 배열 타입은 튜플타입에 할당 못해
//1.
// 타입 : (boolwan | number)[]
const pairLoose = [false, 123];
const pairTupleLoose: [boolean, number] = pairLoose;
// Error: Type '(number | boolean)[]' is not assignable to type '[boolean, number]'
//		Target requires 2 element(s) but source may have fewer.
	- pairLoose 내부에 [boolean, number]가 있는 것을 볼 수 있지만, 타입스크립트는 더 일반적인 (boolean | number)[] 타입으로 유추한다.
    - pairLoose가 [boolean, number] 자체로 선언 된 경우 pairTupleLoose에 대한 값 할당이 허용되었을 것.
    - 하지만 타입스크립트는 튜플타입의 튜플에 얼마나 많은 멤버가 있는지 알고 있기 떄문에 길이가 다른 튜플은 서로 할당할 수 없다.
    
    
//2.
const tupleThree: [boolean, number, string] = [false, 1583, 'Nzinga'];
const tupleTwoExact: [boolean, number] = [tupleThree[0], tupleThree[1]];
const tupleTwoExtra: [boolean, number] = tupleThree;
//Error: Type '[boolean, number, string]' is not assignable to typt '[boolean, number]'.
//		Source has 3 element(s) but target allows only 2.

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

  • 튜플은 구체적인 길이와 요소타입 정보를 가지는 배열로 간주되므로 함수에 전달할 인수를 저장하는데 특히 유용함.
  • 타입스크립트는 ...나머지 매개변수로 전달된 튜플에 정확한 타입검사를 제공할 수 있다.
//1.
const logPair = (name: string, value: number) => {
  console.log('${name} has ${value}')
}
const pairArray = ['Amage', 1]
logPair(...pairArray);
const pairTupleCorrect: [string, number] = []


.
.
.

.
..
.. 미완성.
..
..
.
..
..
.

명시적 튜플 타입

  • 함수에 대한 반환타입 애너테이션처럼 튜플타입도 타입애너테이션에 사용할 수 있다.
  • 함수가 튜플타입을 반환하다고 선언되고 배열 리터럴을 반환한다면 해당 배ㄹ 리터럴은 일반적인 가변ㅣㄹ이의 배열대신 튜플로 간주됨.
//1.
//반환타입: [string, number]
const firstCharAndSizeExplicit = (input: string): [string, number] => {
  return (
    [input[0], input.length]
  );
}
//firstChar타입: string
//size타입: number
const [firstChar, size] = firstCharAndSizeExplicit('Cathay Williams');

const 어서션

  • 명시적타입 애너테이션에 튜플타입을 입력하는 작업은 명시적타입 애너테이션을 입력할 때와 동일한 이유로 좋지않을 수 있다.
  • 즉, 코드 변경에 따라 작성 및 수정이 필요한 구문을 추가해야함.
  • 타입스크립트의 대안 : 값 뒤에 넣을 수 있는 const 어서션인 as const 연산자를 제공한다.
  • const 어서션은 타입스크립트에 타입을 유추할 때 읽기 전용이 가능한 값 형식을 사용하도록 한다.
//1.
//타입: (string | number)[]
const unionArray = [1157, 'Tomoe'];

//타입: readonly [1157, 'Tomoe']
const readonlyTuple = [1157, 'Tomoe'] as const;
	- 배열리터럴 뒤에 as const 가 배치되면, 배열이 튜플로 처리되어야함을 나타냄.
    - const 어서션은 유연한 크기의 배열을 고정된 크기의 튜플로 전환하는 것을 넘어서, 해당 튜플이 읽기 전용이고 값 수정이 예상되는 곳에서 사용할 수 없음을 나타냄
    
    
//2.
const pairMutable: [number, string] = [1157, 'Tomoe'];
pairMutable[0] = 1247;
const pairAlsoMutable: [number, string] = [1157, 'Tomoe'] as const
//Error: The type 'readonly [1157, 'Tomoe']' is 'readonly'
//		and cannot be assigned to the mutable type '[number, string]'.
const pairConst = [1157, 'Tomoe'] as const;
pairConst[0] = 1247;
//Error: Cannot assign to '0' because it is a read-only property.
	- pairMutable은 전형적인 명서적 튜플 타입이므로 수정될 수 있다.
    - 그러나 as const 는 값이 변경될 수 있는 pairAlsoMutable에 할당할 수 없도록하고, 상수 pairConst의 멤버는 수정을 허용하지 않는다.
    - 실제로 읽기전용 튜플은 함수반환에 편리하다.
    - 튜플을 반환하는 함수로부터 반환된 값은 보통 즉시 구조화되지 않으므로 읽기전용인 튜플은 함수를 사용하는데에 방해가 되지않음.
    
    
//3.
//반환타입: readonly[string, number]
const forstCharAndSizeAsConst = (input: string) => {
  return (
    [input[0], input.length] as const;
  )
}
//firstChar타입: string
//size타입: number
const [firstChar, size] = firstCharAndSizeAsConst('Ching Shih');
	- firstCharAndSizeAsConst는 읽기전용 [string, number]를 반환하지만, 이를 사용하는 코드는 해당 튜플에서 값을 찾는 것에만 관심을 둔다.

0개의 댓글