[Type Script] 체크하는 시간을 줄이기 위해 하형 정의를 조금 노력합니다.
26448 단어 TypeScripttech
Type Script에서는 대체로 다음과 같은 경우 형식을 써야 합니다.
any
또는 unknwon
에 정의된 의욕이 없는 라이브러리의 반환값에 유형 정보를 제공할 때기계적으로 시키고 싶지만 지금은 사람이 쓸 수밖에 없기 때문에 어쨌든 귀찮아요.
하지만 형식 정의에 공을 들이면 한꺼번에 가벼워질 수 있을까?이에 따라 평소 사용하는 수법 3가지를 열거하기로 했다.
검은색 마술을 쓰지 않고 직감적으로 쓴 것만 열거했기 때문에 내용을 긴장되지 않게 읽을 수 있었으면 좋겠다.
공통 항목이 없는 객체 유형 전환
공통 없음은 아래 설명된 A와 B의 공통 속성이 전혀 없는 경우를 의미합니다.
type A = {
x: number
}
type B = {
y: number
}
이것은 API와 교환할 때 응답 내용이 상태에 따라 완전히 다른 경우를 자주 겪는다.이러한 API의 응답 유형 정의를 고려합니다.
예컨대
"로그인 전에는
session
속성이 있고, 로그인 후에는 token
속성과 user
속성이 있습니다."이런 패턴.
이것은 다음과 같은 정의가 없습니까?
type UserInfo = {
user?: {...}
session?: string
token?: string
}
네, 모든 것이 완벽합니다.이러다가는 무한 필기형 방어의if문에 빠질 수도 있으니 포기하자.아래와 같이 각 장소의 유형을 잘 정의하는 것이 좋다.
type NoLoginUserInfo = {
session: string
}
type LoginedUserInfo = {
user: {...},
token: string
}
export type UserInfo = NoLoginUserInfo | LoginedUserInfo
이렇게 하면 다음과 같은 in 판정을 통해 한쪽에만 존재하는 키의 존재를 정확하게 각자의 유형으로 추론할 수 있다.그런 판정용 함수를 쓸 필요가 없다.
function checkLogin(userInfo: UserInfo) {
if ("token" in userInfo) {
// userInfo が LoginedUserInfo として推論される
} else {
// userInfo が NoLoginUserInfo として推論される
}
}
이 정도의 유형 검사가 있다면 원래 자바스크립트도 해야 할 것 같다.Type Script의 경우에만 if문을 쓰면 아무리 생각해도 촌스럽기 때문에 이렇게 유형을 정해서 AltJS의 스타일을 보여드리는 게 좋을 것 같아요.
특정 유형의 단서가 있는 대상에 대해
앞의 예와 달리 지금은 대상 내에 특정 종류의 단서 속성이 있는 상황이다.
예를 들어 직원 정보를 표현하는 유형을 고려한다.
type ContractType = "fulltime" | "parttime"
type Employee = {
contractType: ContractType
department: string
salary: number
bonus?: number
period?: number
}
이것은contractTypeisLoginedUser(user: UserInfo): user is LoginedUserInfo
이다. 즉, 정규직은 무기고용이고period,bonus가 없다.또
fulltime
, 즉 아르바이트 직원의 경우 유기 고용이기 때문에 페리코드가 있고 보너스가 없다는 것이다.그러나 이 유형의 정의라면 다음과 같은if문구로 검사할 때 두 번의 번거로움이 발생합니다.
function calcSalary(employee: Employee) {
if (employee.contractType === "fulltime") {
// fulltime なので bonus が仕様上あるはずだが、TypeScriptがそのことを知らないためエラーになる
return employee.salary + employee.bonus
// parttime なので period があるはずだが以下略
} else if (employee.period < Date.now()) {
return employee.salary
} else {
return 0 // 悲しい
}
}
이것은 다음과 같은 방식으로 유형 정의를 해결할 수 있다.type FulltimeEmployee = {
contractType: "fulltime"
department: string
salary: number
bonus: number
}
type ParttimeEmployee = {
contractType: "parttime"
department: string
salary: number
period: number
}
type Employee = FulltimeEmployee | ParttimeEmployee
이렇게 함으로써 다음과 같은 유형 추론 결과를 얻었다.좀 신경 쓰일 수도 있고
function calcSalary(employee: Employee) {
if (employee.contractType === "fulltime") {
// ここで employee が FulltimeEmployee に推論されるためエラーにならない
return employee.salary + employee.bonus
// ここで employee が ParttimeEmployee に推論されるためエラーにならない
} else if (employee.period < Date.now()) {
return employee.salary
} else {
return 0 // 悲しさは変わらない
}
}
parttime
의 유형 정의는 contractType
가 아니지만, 단원 테스트를 잘 쓰면 오류가 무너질 수 있습니다.형식적인 정의에 있어서 모든 노력을 기울일 필요가 없다.
참고로 Redux에서 이 규격을 잘 사용하면 Reducter의 정의가 매우 편안할 것입니다.
const COUNT_UP = "COUNT_UP" as const
const CountUp = (increases: number) => ({
type: COUNT_UP,
payload: {
increases
}
})
const COUNT_DOWN = "COUNT_DOWN" as const
const CountUp = (decreases: number) => ({
type: COUNT_DOWN,
payload: {
decreases
}
})
type Actions = ReturnType<
| typeof CountUp
| typeof CountDown
>
function reducer(state: State, action: Actions): State {
switch(action.type) {
case COUNT_UP: {
return {
...state,
// action.type を手がかりに、 payload の型が推論されている
count: state.count + action.payload.increases
};
}
case COUNT_DOWN: {
return {
...state,
count: state.count - action.payload.decreases
};
}
}
return state
}
nullable의 속성과 잘 어울려요.
Optional Chaning 기능이 있습니다.
nullable 객체
ContractType
에 액세스할 수 있습니다.이것은 사용하기에 의외의 어려움이다. 만약 그렇게 사용한다면 결과적으로undefined가 멈추게 될 것이다.
type Foo = {
hoge?: {
x: number
}
fuga?: {
y: number
}
}
function doSomething(foo: Foo) {
return foo.hoge?.x + foo.fuga?.y // 各項が number | undefined になるので足し算が出来ない
}
어떻게 사용하면 좋을까, 이런 말과 주제가 좀 다르기 때문에 여기서 이 Optional Chaning의 존재를 전제로 유형 정의를 검토해 보려고 합니다.예를 들어 다음과 같이 과감하게
hoge?.fuga?.piyo
와의 유니온형을 시도한다.React의 Component로 정의하면 편리합니다.
type Props = {
width: number | undefined
height: number | undefined
}
export const Rectangle = (props: Props) => {
const { width = 100, height = 100 } = props
return // 以下略...
}
undefined
와 width?: number
의 차이는 이 속성이 존재하지 않도록 허용하는지 여부에 있다.상기 Component는 호출 측에서
width: number | undefined
와 width
의 속성을 지정해야 한다.<Rectangle /> {/* width と height がないというエラーになる */}
이것은 폼 입력이 없을 때도 기본값을 사용해서 이동할 때 편리하기를 바랍니다.const App = () => {
const [size, setSize] = useState<{width: number, height: number} | null>(null);
return (
<>
<input onChange={e => {
const values = e.target.value.split(",")
setSize({ width: parseInt(values[0]), height: parseInt(values[1]) })
}} />
<Rectangle width={size?.width} height={size?.height} />
</>);
};
응, 솔직히<Rectangle width={size?.width ?? 100} height={size?.height ?? 100} />
처럼null합체산자height
와 조합하여 사용하면 이해하기 쉽고 묘사도 간결하다.(상기 예에서parseInt는 NaN을 반환할 가능성이 있지만 NaN은 사용하더라도
??
보통 왼쪽 값으로 되돌아오기 때문에 안전성은 어느 것을 사용하든지 변하지 않는다)끝맺다
이번에는 기억하기 쉽고 직관적으로 쓴 성어를 소개했다.
아마도 CondiionalTypes 같은 흑마술을 쓰면 더 복잡한 일이 생길 수 있겠지만, 솔직히 이 점에 쓰지 않고 아무리 노력해도 자바스크립트 부분으로 전환할 수 있다면 앱은 평생 완성되지 않을 것이고, 개인적으로 너무 많이 하면 성가가 좋지 않을 것이라고 생각한다.
Template Literals는 다양한 방법을 적용할 수 있기 때문에 생각나는 대로 기사를 쓴다.
그럼 편한 타입 스크립트 생활을 하세요.
Reference
이 문제에 관하여([Type Script] 체크하는 시간을 줄이기 위해 하형 정의를 조금 노력합니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/happou31/articles/2cc0f62ac50f7e텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)