alias(별칭) 타입
- 재사용에 좋음 / 변수에 할당하는 방식
type Age = number;
type Name = string;
type Player = {
readonly name:Name,
age?:Age // optional
}
const playerMaker = (name:string) : Player => ({name});
const suuun = playerMaker("seon");
suuun.age = 32;
//suuun.name="dddd"; //readonly가 있으면 읽기 전용이므로 최초 선언 후 수정 불가
const playersuuun:Player = {
name:"seon"
}
함수의 리턴값에 타입을 지정하는 방식
- 위의 화살표 함수와 같음
function playerMaker2(name:string) : Player{ //argument 역시 타입을 지정할 수 있다
return{
name //name:name
}
}
//추론할수 있는 타입에는 굳이 써주지 않음
/* undefined, null, any
any: 아무 타입
undefined: 선언X 할당X
null: 선언O 할당X */
object
const numbers:readonly number[] =[1,2,3,4];
//numbers.push(1) - number[]가 아니라서 에러
const names:readonly string[] = ["1","2"]; //map,filter은 가능하나 push는 불가능
//turple - 정해진 갯수의 요소를 가져와야 하는 array를 지정할 수 있음
const player:[string,number,boolean] = ["suuun",12,true];
//player[0]=1; //type이 string이므로 에러 발생
const player2:readonly [string,number,boolean] = ["suuun",12,true];
//readonly를 붙일경우 string값인 suuun을 바꿀수 없음, 나머지도 마찬가지도 변경 불가
선택적타입
- 우리가 쓰는 옵셔널체이닝은 그값 | (또는) undefined 로 되어있음
let a : undefined = undefined;
let b : null = null;
any
- 타입스크립트 규칙을 안쓰고 싶을때 사용 - 쓰는순간 자스처럼 사용할 수 있음
let c = [];
let d:any[]=[1,2,3,4];
let e:any = true;
d+e; //typescript에서는 허용되지 않는것이 허용되어버림
//하지만 any를 써야할 때가 생기기 때문에 신중하게 써야함
void, never, unknown
1.unknown - 타입을 모르는 경우
let a:unknown;
//let b = a+1; //a의 타입을 모르므로 에러발생
//따라서 조건문 안에 써줘야 함
if(typeof a === 'number'){
let b = a+1;
}
//a.toUpercase //에러발생
if(typeof a === 'string'){
let c = a.toUpperCase();
}
//2.void - 아무것도 return 하지 않는 함수를 대상으로 사용
function hello(){ //hello():void 로 쓸수 있음 - 보통 따로 지정하지않음
console.log('x');
}
//3.never - 절대 return하지 않을경우 - 보통 함수에서 예외가 발생할때
function hi():never{
throw new Error('error'); //return없이 오류 발생시킬경우
}
//타입이 2가지 일때도 사용 할수 있는 never
function realName(name:string|number){ //타입을 두가지 지정했을때 - 파라미터를 string 또는 number로 지정(or 개념)
if(typeof name === 'string'){
name
}else if(typeof name === 'number'){
name
}else{ //위에 name을 지정한 타입일때의 조건문으로 다쓰고 나면 두타입을 모두 확인 해줬기 때문에 else 안에 쓴 name은 never이 된다.
name
}
}
call signatures, 다형성, 오버로딩, 제네릭
// function add(a:number,b:number):number{ //return 값이 :number - 리턴형태는 number이므로 생략가능
// return a+b;
// }
//위와 같음
//const add = (a:number,b:number) => a+b;
/**
* 1.call signatures - 마우스를 올렸을때 함수를 어떻게 호출해야하는 것인지 어떤타입을 써야하는지 함수의 반환타입을 알려주는 것
* function signatures 이라고도 부름
*/
//타입을 분리하여 쓸수 있음
//1)
type Add = (a:number,b:number) => number; //타입구현 - 파라미터 타입과 리턴타입을 미리 정의
const add:Add = (a,b) => a+b; //코드구현
//const add2:Add = (a,b) => {a+b}; //에러발생
//2.오버로딩 - method 오버로딩이라고도 부름 : 여러 call signatures가 있는 함수
//2) 1)의 형태를 이렇게 바꿀 수도 있음 - 오버로딩 때문
type Add2 = {
(a:number,b:number) :number
}
//오버로딩을 쓰는경우는 예를들어 리액트 nextjs에서 라우터 때 push로 string도 보낼수 있지만 객체로도 보낼수 있음
//보통 외부 라이브러리에서 많이 쓰임
//오버로딩 예시
type Config = {
path:string,
state:object
}
type Push = {
(path:string):void
(config : Config):void
}
const push:Push =(config) => {
if(typeof config === 'string'){
console.log(config)
}else{
console.log(config.path,config.state)
}
}
//파라미터 갯수가 다를때 - 이경우 보다는 위의 경우가 더 많이 쓰임
//매개변수의 개수는 동일해야 사용할 수 있지만 옵션 매개변수를 명시적으로 기록하므로 아래와 같이 쓸수 있는것
type Add3 = {
(a:number,b:number) : number
(a:number,b:number,c:number) : number
}
const add3:Add3 = (a,b,c?:number) => {//파라미터 갯수가 다를때 옵셔널 체이닝을 써줘야함
if(c) return a+b+c;
return a+b;
}
add3(1,2);
add3(1,2,3);
//다형성 - 여러가지의 구조를 가지는 것
type SuperPrint = {
// (arr:number[]):void;
// (arr: boolean[]):void;
// (arr: string[]):void;
//concrete type을 알수 없을때 위와 같이 쓰면 모든 나올수 있는 경우의 수로 다 만들어야 하므로 제네릭을 사용한다.
/*
1.제네릭을 사용한다고 알려줘야함 - 보통 T,V를 많이씀
*/
//<T>(arr:number[]):void; //원하는것으로 써주어도 됨
<TypePlaceholder>(arr:TypePlaceholder[]):void; //앞의 제네릭과 타입부분을 제네릭 이름으로 맞추어준다.
}
const superPrint:SuperPrint = (arr) => {
arr.forEach(i => console.log(i));
}
superPrint([1,2,3,4,5]);
superPrint([true,false,true]);
superPrint(["1","2","3"]); //concrete type
superPrint(["1",false,true,2]);
//다형성 - 여러가지의 구조를 가지는 것
//제니릭 - 타입의 placeholder 같은 것 - 대체된다는 뜻
//제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다.
- any와의 generics 차이점
1.해당 타입에 대한 정보를 잃지 않는다.
2.함수를 반환하는데 있어 'any'는 받았던 인수들의 타입을 활용하지 못한다.
3.타입스크립트에서 제네릭을 통해 인터페이스, 함수 등의 재사용성을 높일 수 있습니다.
type SuperPrint2 = {
// (arr:number[]):void;
// (arr: boolean[]):void;
// (arr: string[]):void;
//concrete type이 어떻게 나오는지 알 수 없을때 위와 같이 쓰면 모든 나올수 있는 경우의 수로 다 만들어야 하므로 제네릭(타입을 유추할 수 있으므로)을 사용한다.
/*
1.제네릭을 사용한다고 알려줘야함 - 보통 T,V를 많이씀
*/
//<T>(arr:number[]):void; //원하는것으로 써주어도 됨
//<TypePlaceholder>(arr:TypePlaceholder[]):TypePlaceholder; //앞의 제네릭과 타입부분을 제네릭 이름으로 맞추어준다.
<T>(arr:T[]):T
}
const superPrint2:SuperPrint2 = (arr) => arr[0]
const a = superPrint2([1,2,3,4,5]);
const b = superPrint2([true,false,true]);
const c = superPrint2(["1","2","3"]); //concrete type : number, boolean, void 등 지금까지 배운 타입
const d = superPrint2(["1",false,true,2]);
//type SuperPrint = <T>(a:T[]) => T //<T>로 안쓰고 그냥 T를 쓰게 되면 타입으로 인식하므로 <>안에 첫글자를 대문자로 써줘야 제네릭으로 인식함
//제네릭을 추가할경우
type SuperPrint = <T,M>(a:T[],b:M) => T
//재네릭 순서로 재네릭 타입을 알 수 있다.
const superPrint:SuperPrint = (a) => a[0];
//위의 방식을 아래의 함수 선언 방식으로 바꿀 수 있음
function superPrint<T>(a: T[]){
return a[0];
}
// superPrint([1,2,3,4,5]);
// superPrint([true,false,true]);
// superPrint(["1","2","3"]);
// superPrint(["1",false,true,2]);
superPrint([1,2,3,4,5],"");
superPrint([true,false,true],1);
superPrint(["1","2","3"],false);
superPrint(["1",false,true,2],[]);
//보통제네릭은 라이브러리 개발이나 다른 개발자의 기능을 개발할때 사용함
//타입을 생성할수도 있고 확장 할 수도 있음
#재네릭 사용하기
type Player<E> = {
name:string
extraInfo:E
}
//
type SuuunExtra = {
favFood:string
}
// const suuun:Player<{favFood:string}> = {
// name:"suuun",
// extraInfo:{
// favFood:"jjajang"
// }
// }
//위와 같음
type SuuunPlayer = Player<{favFood: string}> //SuuunExtr는 {favFood: string} 대신 들어갈 수 있음
//type SuuunPlayer = Player<SuuunExtra>
const suuun:SuuunPlayer = {
name:"suuun",
extraInfo:{
favFood:"jjajang"
}
}
//재네릭의 재사용성 - 변경될수 있는 타입이라면 재네릭을 사용함
const Uk:Player<null>={
name:"Uk",
extraInfo:null
}
++react에서는 useState가 typescript를 받는다
ex)useState<number>(0) - number 타입의 useState
타입스크립트의 객체지향
📌접근 가능한 위치
구분 선언한 클래스 내 상속받은 클래스 내 인스턴스
private ⭕ ❌ ❌
protected ⭕ ⭕ ❌
public ⭕ ⭕ ⭕
TIP)
private를 사용하면 상속받은 클래스 안에서 마저도 this 사용해 접근 불가능
그래서 protected를 사용하면 상속받은 클래스 안에서 this 사용해 접근 가능
물론 protected로 지정된 것들은 외부에서 사용이 불가능
추상클래스 안에 메소드는 적어서는 안되고 call signature만 적어야 함
추상클래스 안의 메소드는 결국 구현이 되지 않는다고 나옴
https://velog.io/@760kry/TypeScript-OOP-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5
타입스크립트로 calss만들기
class Player{
constructor(
private firstName:string,
private lastName:string,
public nickName:string
){}
}
const suuun = new Player("suuun","kim","suuuny");
//suuun.nickName 은 public이라 외부에서 접근가능하나 private 접근 불가(suuun.lastName)❌
abstract = 추상클래스
- 다른 클래스가 상속 받을 수 있는 클래스
abstract class User{
constructor(
private firstName:string,
protected lastName:string,
public nickName:string //public: 모든 클래스에서 접근 가능
){}
//추상클래스와 추상메서드
abstract getNickName():void //1.추상메서드 : 추상클래스 안에 call signatures만 적어주기 - 구현되는 코드가 없는 메서드
getFullName(){ // private getFullName() 을쓰면 외부에서 접근할 수없다, 클래스와 마찬가지로 - 아무것도 안붙은것은 기본적으로 public
return `${this.firstName} ${this.lastName}` //private User클래스의 인스턴스나 메서드에서만 접근가능, 외부불가
}
}
//const suuuny = new User("1","2","3") //추상 클래스는 직접 새로운 인스턴스를 만들 수 없음 - 자스에서는 가능
class Player2 extends User{ //Player2가 User를 상속함
//2.추상메서드는 추상 클래스를 상속받은 모든것들을 반드시 구현(implement)해야하는 메서드, 이곳에서 정의해줘야 에러가 안뜸
getNickName(){
//console.log(this.firstName); //private 이므로 인스턴스에서 접근불가, 자식클래스에서 접근불가❌
console.log(this.lastName); //protected 라서 상속받은 곳에서는 접근가능하나 외부에서는 불가능
}
}
const suuuny = new Player2("suuun","kim","suuuny");
suuuny.getFullName(); //상속받았기 때문에 추상 메서드 사용가능
//suuuny.lastName; //protected이므로 클래스 밖(외부)에서 접근 불가능
//추상메서드를 만들때는 메서드를 클래스 안에서 구현하지 않아야 함(메서드:클래스안에 존재하는 함수)
+++public 인대 외부에서 수정을 막고 싶을경우에는 public readonly nickName 를 붙이면 된다.
정적메서드(static)
https://ko.javascript.info/static-properties-methods
타입스크립트로 사전만들기(소스를 변경하면서 콘솔창을 확인하세요😊)
타입스크립트 클래스
'typescript' 카테고리의 다른 글
Record type (0) | 2025.06.04 |
---|---|
여러 이미지를 호버하여 이미지를 변경할때 type 정의 (0) | 2025.05.20 |
타입스크립트_2(feat.노마드코더) (0) | 2023.03.17 |
typescript (0) | 2023.01.11 |