복습 차원에서 타입스크립트 다시 정리하기~!
인간은 망각의 동물이니까..
인덱싱 타입선언
interface StringArray {
[index: number]: string;
}
let arr: StringArray = ['a','b','c'];
arr[0]; // 'a'
arr[0] = 10; // 타입 오류 발생 (string에 할당할 수 없다)
딕셔너리 타입선언
interface StringRegexDictionary {
[key: string] : RegExp; // 정규표현식 타입
}
let obj: StringRegexDictionary = {
//sth: /abc/
cssFile: /\.css$/, // css 파일 정규식으로 작성
jsFile: /\.js$/, // js로 끝나는 파일
}
// 장점
Object.keys(obj).forEach(function(value){
// 이 안에 들어오는 값들의 정의가 string이 된다
// 자동으로 value가 string으로 추론된다.
})
인터페이스 확장 (상속)
interface Person {
name: string;
age: number;
}
interface Developer extends Person {
language: string;
}
let capt: Developer = {
// Person 타입도 추가해주어야 에러가 안난다
name: 'juur';
age: 22;
language: 'ts';
}
OOP(객체지향 프로그래밍) Object Oriented Programming
무엇이냐면 !)! 정리 추가하기.
타입 별칭은 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수 의미
type Person = {
name: string;
age: number;
}
interface와 type의 차이점
타입 별칭은 새로운 타입 값을 하나 생성하는 것이 아니라 정의한 타입에 대해 나중에 쉽게 참고할 수 있게 이름을 부여하는 것과 같다
interface 사용시 해당 타입 마으스오버 + command 클릭 = 바로가기
type은 확장이 되지 않는다. <가장 큰 차이점>
타입가드 : if문 typeof로 타입확인하여 특정 동작하도록 하는 것
특정 타입으로 타입의 범위를 좁혀나가는(필터링 하는) 과정
let hee : string | number | boolean;
const logMessage = (value: string | number) => {
if(typeof value === 'number') {
value.toLocaleString(); // 메소드 바로 사용 가능
}
if(typeof value ==='string') {
value.toString();
}
throw new TypeError('value must be string or number'); // 나머지 타입은 타입에러 발생시킴
}
| : 모든 속성 접근 가능하지 않고, 공통으로 갖고 있는 속성만 접근 가능함 혹은 타입가드이용하면 됨
갖고 있는 타입 속성으로 노출되고 접근 가능
속성 중 하나라도 빠지면 타입에러 발생
특정 값들의 집합을 의미하는 자료형 (ex. 드롭다운, 정해져있는 목록)
별도로 값 지정하지 않으면, 숫자형 0부터로 자동지정
enum Shoes {
Nike,
Adidas
}
const myShoes = Shoes.Nike;
console.log(myShoes); // 0
enum Shoes {
Nike:'나이키',
Adidas:'아디다스'
}
const myShoes = Shoes.Nike;
console.log(myShoes); // 나이키
예외처리 케이스 줄어들 수 있다.
enum Answer {
Yes ='Y',
No = 'N',
}
function askQuestion(answer: string) {
// 단순히 아래처럼 문자열 비교가 아니라 enum 을 활용해서 좀 더 정확하게
// if (answer ==='yes') {console.log('정답입니다')}
if (answer === Answer.Yes) {console.log('정답입니다')}
if (answer === Answer.No) {console.log('오답입니다')}
}
askQuestion(Answer.Yes);
// XX => askQuestion('Yes'); // Enum 에서 제공하는 값만 넘길 수 있다.
constructor() {} => 초기화 메소드
class Person {
// 클래스 로직 :객체 기본속성, 혹은 api 등 설정 가능
constructor(name, age) {
console.log('생성 되었습니다');
this.name = name;
this.age = age;
}
}
const hee = new Person('hee', 300); // 생성
console.log(hee); // 객체 생성 Person {name: 'hee', age: 300}
기본 전제 > JS가 프로토타입 기반 언어이다
자바스크립트 프로토타입 (class가 프로토타입 )
프로토타입을 이용한 상속
admin.__proto__
를 통해 user를 상속받는다.
admin 객체를 추가할 수 있고, admin.name과 admin.age에도 접근 가능하다.
Built-in Javascript API 또는 Javascript Native API
=> Prototype을 일상생활에서 이미 쓰고 있었다.
단순히 객체정보 확장 뿐만 아니라, 기능들을 바로 바로 쓸 수 있다.
클래스라는 것은,
기존 문법의 syntatic sugar(보기 좋은 코드) 정도의 느낌 = 추가적 기능 = 기존 제공하던 성질 변경없이 문법만 추가
1) ES6 이전
class 없이 사용 가능!
function Person(name, age) {
this.name = name;
this.age = age;
}
const hee = new Person('희', 300);
2) ES6 이후
자바 개발자 혹은, 객체지향 언어 개발자들을 위해, 자바스크립트를 쓰기 수월하게 class 문법 제공한 것
하지만 babel 통해 돌려보면, 실질적으론 위처럼 생성자 함수를 썼다는 것을 알 수 있다.
기존 prototype 기반 유지, class 없이 충분히 위 함수처럼 사용 가능하다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const hee = new Person('희2', 300);
타입스크립트에선 class 최상단에 멤버변수(속성들) 타입을 선언해줘야 한다. constructor에 들어오는 파라미터 타입도 구체적으로 정할 수 있다
또, 변수의 유효 범위도 설정할 수 있다.
class Person {
private name: string;
public age: number; // 기본 public
readonly log: string; // 읽기만 가능
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class App extends React.Component { ... }
function App() {
return <div>Hello World</div>
}
타입을 마치 함수의 파라미터처럼 사용하는 것을 의미
함수의 이름 바로 뒤에 <T>
라는 코드 추가. 그리고 함수의 인자와 반환 값에 모두 T
라는 타입을 추가. 이렇게 되면 함수를 호출할 때 넘긴 타입에 대해 타입스크립트가 추정할 수 있게 된다.
따라서, 함수의 입력 값에 대한 타입과 출력 값에 대한 타입이 동일한지 검증할 수 있게 된다.
function logText<T>(text: T):T {
return text;
}
// 두 가지 방법으로 호출 가능
// #1 호출시점 타입 넘겨주기 가능
const text = logText<string>("Hello generic!");
// #2
const text2 = logText("Hello generic!!");
동일 코드를 타입을 받기 위해 불필요하게 함수 사용하는 경우를 줄일 수 있다.
만약 유니온타입으로 쓴 경우엔, 공통으로 쓸 수 있는 메소드만 미리 보여주기 가능하다.
반환값이 문자여도, number 타입을 유니온타입으로 추가해주었기에
ex.split('')사용 시, 타입오류가 뜨게 된다.
=> 제네릭 사용 시, 이런 오류가 해결된다!
같은 코드를 호출시점에 타입 정의해주어 타입추론해서 반환값까지 알 수 있게 된다.
function logText(text: string | number) {
console.log(text);
// text. toLocaleString / toString / valueOf 뜸
return text;
}
const a = logText('a');
a.split(''); // 사용 시에 반환 타입이 string/number 2개로
// 이 부분에서 ts오류가 뜨게 된다.
interface Dropdown <T>{
value: T,
selected: boolean
}
const emails:Dropdown<string>[] = [
{ value: 'naver.com', selected: true },
{ value: 'gmail.com', selected: false },
{ value: 'hanmail.net', selected: false },
];
const numberOfProducts :Dropdown<number>[]= [
{ value: 1, selected: true },
{ value: 2, selected: false },
{ value: 3, selected: false },
];
function createDropdownItem<T>(item:Dropdown<T>) {
const option = document.createElement('option');
if(typeof item.value ==='string') {
option.value = item.value.toString();
option.innerText = item.value.toString();
}
option.selected = item.selected;
return option;
}
// NOTE: 이메일 드롭 다운 아이템 추가
emails.forEach(function (email) {
const item = createDropdownItem<string>(email);
const selectTag = document.querySelector('#email-dropdown');
selectTag?.appendChild(item);
});
제네릭 더 엄격하게 쓸 때!
split('') ,forEach 등 배열 메소드 사용하려고 할 때, T를 제한해서 T[]로 사용한다.
function logTextLength<T>(text: T[]):T[] {
console.log(text.length);
text.forEach((text)=> console.log(text))
return text;
}
logTextLength<string>(['hi','hee'])
제네릭에 타입제한이 생긴 것!
함수호출하는 시점 제네릭의 타입만 잘 넘겨주면 정확하게 타입 잘 선언한 모습. 인터페이스 속성만 받도록 제한하겠다.
ShoppingItem의 키들 중 한 가지가 바로 T로 들어올 것이란 의미
변수를 선언하거나 초기화 할 때 타입이 추론된다. 이외에도 변수, 속성, 인자의 기본 값, 함수의 반환 값 등을 설정할 때 타입 추론이 일어난다.
함수 호출할 때, b를 넘기지 않으면 기본적으로 10의 값을 넘긴다.
함수 내부에 변수 선언하면 c의 타입은 string, 타입 추론일어남
문자열 + 숫자 = 문자가 나오게 된다.
10 + '10' = '1010'
function getB(b=10) {
const c = 'hi';
return b+c; // '10hi'
}
Best Common Type : TS의 알고리즘, 가장 근접한 타입 추론
모든 값들을 union으로 묶어간다.
https://code.visualstudio.com/docs/languages/typescript
nodeModules 하위 파일 확인하면 다음과 같다
세부 내용 읽어보고 도움될 것 같은 부분은 따로 정리하는 것으로!
타입스크립트보다 개발자가 타입 더 잘 알 때, 타입단언 사용!
일반적으로 document.속성에서 제공하는 속성들
웹페이지 태그정보로 접근하고, 조작할 수 있는 api
대표적으로, document.querySelector()
// DOM API 조작
// <div id = "app">hi</div>
const div = document.querySelector('div');
() 안에 'div' 선언하면 #app으로 작성했을 때보다 구체적인 태그 타입이 입력된다. vs내부에서 lib.dom.d.ts 타입이 선언되어 있기 때문이다.
div가 없을 수 있다.-> 이 경우
const div = document.querySelector('div') as HTMLDivElement;
if(div) { div.innerText } 식으로 사용
타입단언하지 않으면 null타입도 추가된다.
유니온으로 타입이 되어 있는 경우, 공통 속성이 아니면 속성값 없다고 경고가 뜬다.
타입가드를 적용하면 에러가 뜨지 않는다 ! 예제