20250408 데브코스 프론트엔드 Day26
💡 인사이트
- 같은 이름의 변수 또 선언해서 뜨는 에러는 {} 안에 코드를 작성하면 해결된다.
- 타입을 지정한 배열에 push를 할때, push할 값으로는 아무 값이나 가능하긴 하지만 push할 값이 push하려는 배열에서 지정한 타입과 맞아야 오류가 나지 않는다.
하지만 타입 추론에 의해서 타입스크립트가 타입을 자동으로 추론이 가능하면 에러가 나지 않는다. 그렇다고 아예 다른 타입을 push하는건 보정해주지 못한다.- 100n은 그냥 100이다.
- 변수명에 마우스 가져가면 추론된 타입이 나타난다.
- 타입을 지정하지 않아도 에러가 발생하지 않기 때문에(타입 추론에 의해) 타입을 명시적으로 적겠다하면 적으면 되고, 아니면 그냥 타입추론으로 그대로 써도 된다.
타입 추론의 경우 완벽하게 추론되지 않는 경우가 있기 때문에, 타입스크립트 레벨(프레임워크를 쓰지 않았을 때)에서는 명시적으로 타입을 적어주는게 좋은 것 같다고 한다.
리액트의 관점에서는 타입추론으로 문제가 되지 않는다면 굳이 안적어도 더 편한 것 같다고 한다.
-> 적느냐 마느냐는 이후 회사 컨벤션에 따라서 하면 된다.- 타입 추가는 동적으로 할 수 없다.
타입스크립트
타입을 지정하자.
타입 지정후에 해당 변수에 다른 자료형을 할당하려고 하면 에러가 발생한다.
타입별 지정 방법
문자열
let name: string = "Alice";
숫자
let age: number = 10;
- 10진수든, 16진수든, 2진수든, 실수든 다 number
논리형(boolean)
let bool: boolean = true;
- falsy -> false, 0, -0, “”, undefined, null, NaN. (false로 평가되는 값)
- truthy -> falsy를 제외한 모든 값. (true로 평가되는 값)
- cf.
let bool: boolean = "";
또는let bool: boolean = null;
는 에러가 발생하는데, ““와 null은 정확히 false인 것이 아니기 때문에 자바스크립트가 자동으로 평가해주는 애들이 아니기 때문이다.
null
let nothing: null = null;
undefined
let notDefined: undefined = undefined;
아무거나 허용(any)
let anything: any = 10;
- 위처럼 anything을 any로 타입 지정하면, anything에 “A”(문자열)을 재할당해도, true(boolean)을 재할당해도 에러가 나지 않는다.
- 즉, any는 타입을 검사하지 않겠다는 타입이고, 타입 검사를 무력화하기 때문에 남용을 피해야 함.
unknown
let input: unknown = "Hello";
- 위처럼 input을 unknow으로 타입 지정하면, input에 다른 타입을 재할당해도 그 당시에는 에러가 나지 않지만, 이후 실행할 때 에러가 나면 에러가 발생한다.
- 실행할 때 에러가 난다?
예를 들어input = 3.14;
로 할당하고,console.log(input.toFixed(2));
를 실행하면 에러가 발생한다.
input이 알 수 없는 타입이므로 input에 number이 들어가 있을 것을 확신할 수 없기 때문에 toFixed를 할 수 없기 때문이다. - 즉, unknown은 타입을 검사하지 않지만 그 값을 사용하려고 할 때는 타입을 검증한다. 따라서 any보다는 unknown이 좀 더 안전하지만 둘 다 걷어내야 할 타입이다.
배열
let arr : 배열요소타입[] = [값]
- 빈 배열 타입 지정 :
let arr: [] = [];
- 배열 요소가 어떤 타입인지에 따라서 달라진다.
- let 배열명 : 배열요소타입[] = [값]
- 숫자 :
let numArr: number[] = [10, 20];
- 문자열 :
let strArr: string[] = ["a", "b", "c"];
- boolean :
let boolArr: boolean[] = [true, false];
- undefined :
let undefinedArr: undefined[] = [undefined, undefined];
- null :
let nullArr: null[] = [null, null];
- object :
let objArr: object[] = [{}, {}];
또는let objArr: {}[] = [{}, {}];
- matrix :
let matrix: number[][] = [[1, 2, 3], [4, 5, 6], [7, 8, 9],];
- 먼저 큰 덩어리 [] 적고, 그 안에 있는게 number 배열이니까 [] 앞에 number[] 적으면 됨.
- 다 접어보고 보이는 타입부터 뒤쪽에 적으면 된다.
- 먼저 큰 덩어리 [] 적고, 그 안에 있는게 number 배열이니까 [] 앞에 number[] 적으면 됨.
- let 배열명 : 배열요소타입[] = [값]
튜플
let mixArr: [number, string] = [10, "A"];
- 특정 형태를 갖는 배열일 때, 어떤 인덱스가 어떤 타입의 값인지 적어준다.
bigInt
let sum: bigint = 123456789012345678901234567890n + 100n;
- bigInt는 숫자 뒤에 n을 붙여서 나타내는 큰 숫자를 정교하게 처리할 수 있는 자료형이다.
- bigint와 그냥 number는 함께 사용하지는 못한다.
객체
let obj: Record<string, never> = {};
- 빈 객체 타입 지정 :
let obj: Record<string, never> = {};
- 모든 타입은 결국 object에서 파생된 거다 보니까, 그냥
let obj: {} = {};
를 하면 원하는대로 동작하지 않는다.(obj에 null과 undefined를 제외한 모든 값을 재할당하는 것을 허용하게 됨.) let obj: object = {};
도[]
과함수
재할당이 가능하기 때문에 빈 객체를 선언하고 싶을 때 적절하지 않다.- 빈 객체는
let obj: Record<string, never> = {};
처럼 utility 타입으로 지정해야 하고, 이것은 객체의 키 값은 문자열이고 값은 아무것도 올 수 없다는 뜻을 갖는다. 속성값으로 어떤 값도 가질 수 없다는 그게 곧 빈객체이기 때문에 이 방법을 사용해서 빈 객체의 타입을 지정한다.
- 모든 타입은 결국 object에서 파생된 거다 보니까, 그냥
- 정확하게 각 속성값이 무슨 타입인지 각각 지정한다.
- let user: {name: string; age: number} = {name : "ys", age: 25};
- object로 객체의 타입을 지정하는 것도 권장되지 않는데, 속성을 추가할 때 에러가 발생하기 때문이다.
또 각 속성값이 무슨 타입인지 모두 지정하면 자동완성 기능이 활성화되는데, object로 적으면 자동완성 기능이 활성화 되지 않는다.
또한 타입이 불분명해지는 문제가 있기 때문에 정확하게 속성값의 타입을 하나하나 적는걸 권장한다.
- object로 객체의 타입을 지정하는 것도 권장되지 않는데, 속성을 추가할 때 에러가 발생하기 때문이다.
- 쉽게 하는 방법은 객체를 그대로 복사해서 변수명 다음에 타입으로 지정해줄 수 있게 : 찍고 붙여넣고, 값(ie.
"ys"
)을 타입(ie.string
)으로 변경한다.
- let user: {name: string; age: number} = {name : "ys", age: 25};
그런데 사실 타입을 지정하지 않아도 에러가 발생하지 않는다.
타입스크립트에는 타입 추론이라는 시스템이 내장되어 있기 때문이다.
타입추론
변수에 할당 되는 값을 보고 타입스크립트 컴파일러가 타입을 추론해주는 현상.
주의할 점은 undefined와 null이 할당된 변수는 any로 타입을 추론한다.
이유는 나중에 다른 값으로 할당하려고 비워두는거일테니 알아서 any로 추론해준다.
이미 추론을 해주기 때문에 그냥 변수에 마우스 갖다대고 복붙하면 쉽다.
타입을 지정하지 않아도 에러가 발생하지 않기 때문에(타입 추론에 의해) 타입을 명시적으로 적겠다하면 적으면 되고, 아니면 그냥 타입추론으로 그대로 써도 된다.
타입 추론의 경우 완벽하게 추론되지 않는 경우가 있기 때문에, 타입스크립트 레벨(프레임워크를 쓰지 않았을 때)에서는 명시적으로 타입을 적어주는게 좋은 것 같다고 한다.
리액트의 관점에서는 타입추론으로 문제가 되지 않는다면 굳이 안적어도 더 편한 것 같다고 한다.
readonly & ?
객체 내에서 사용할 수 있는 readonly
와 ?
가 있다.
readonly
객체 내부에 타입 지정할 때 이후에 그 속성값이 변경되지 않았으면 한다면 readonly를 적어주면 된다.
let obj: {
readonly name: string;
age: number;
} = {
name: "ys",
age: 20,
};
obj.name = "jw";
//////
// TSError : Cannot assign to 'name' because it is a read-only property
옵셔널 속성 ?
optional 속성을 지정하는 것인데, 추후에 객체에 추가될 속성을 지정할 수 있다.
let obj: {
name: string;
age: number;
gender?: string;
} = {
name: "ys",
age: 20,
};
obj.gender = "Female";
console.log(obj);
//////
// { name: 'ys', age: 20, gender: 'Female' }
Leave a comment