(저희 팀과 함께) TypeScript 및 Svelte(우리 모두가 싫어하는 JavaScript 및 React)로 애플리케이션을 다시 작성하기 시작했을 때 다음과 같은 문제에 직면했습니다.
HTTP 응답의 가능한 모든 본문을 안전하게 입력하려면 어떻게 해야 하나요?
이것이 당신에게 종소리를 울리나요? 그렇지 않다면 아마도 당신은 "그 중 하나"일 것입니다. 헤헤. 그림을 더 잘 이해하기 위해 잠시 다른 이야기를 해보자.
이 지역이 탐험되지 않은 것처럼 보이는 이유
아무도 HTTP 응답의 "가능한 모든 본문"에 관심을 두지 않는 것 같습니다. 이미 HTTP 응답을 위해 만들어진 항목을 찾을 수 없었기 때문입니다(아마도 ts-fetch). 이것이 왜 그런지에 대한 논리를 빠르게 살펴보겠습니다.
사람들이 다음과 같은 이유로 아무도 신경 쓰지 않습니다.
행복한 경로만 고려하세요. HTTP 상태 코드가 2xx일 때의 응답 본문입니다.
사람들이 다른 곳에서 직접 입력합니다.
#1의 경우, 개발자(특히 경험이 없는 개발자)는 HTTP 요청이 실패할 수 있으며 실패한 응답에 전달된 정보가 일반 응답과 완전히 다를 가능성이 높다는 사실을 망각하고 있다고 말하고 싶습니다.
#2에서는 ky 및 axios와 같은 인기 있는 NPM 패키지에서 발견된 큰 문제를 살펴보겠습니다.
데이터 가져오기 패키지의 문제
내가 아는 한 사람들은 ky 또는 axios와 같은 패키지를 좋아합니다. 그 이유 중 하나가 OK가 아닌 HTTP 상태 코드에 오류를 발생시킨다는 것입니다. 언제부터 괜찮았어? 이후로. 그러나 분명히 사람들은 이것을 받아들이지 않습니다. 사람들은 만족스럽지 않고 OK가 아닌 응답에 오류가 발생하는 것에 만족합니다.
잡을 시간이 되면 사람들이 OK가 아닌 신체를 입력한다고 상상해 봅니다. 정말 엉망이고 코드 냄새가 나요!
try..catch 블록을 분기 문으로 효과적으로 사용하고 있지만 try..catch는 분기 문이 아니기 때문에 이는 코드 냄새입니다.
그러나 분기가 try..catch에서 자연스럽게 발생한다고 주장하더라도 이것이 여전히 나쁜 또 다른 큰 이유가 있습니다. 오류가 발생하면 런타임에서 호출 스택을 해제해야 합니다. 이는 if 또는 switch 문을 사용한 일반 분기보다 CPU 주기 측면에서 훨씬 더 비용이 많이 듭니다.
이 사실을 알면 단지 try..catch 블록을 오용하여 성능 저하를 정당화할 수 있습니까? 나는 아니오라고 말한다. 프론트엔드 세계가 이것에 완전히 만족하는 이유는 단 한 가지도 없습니다.
이제 제가 추론한 내용을 설명했으니 본론으로 돌아가겠습니다.
문제, 세부사항
HTTP 응답은 상태 코드에 따라 다른 정보를 전달할 수 있습니다. 예를 들어, PATCH HTTP 요청을 수신하는 api/todos/:id와 같은 todo 엔드포인트는 응답 상태 코드가 400일 때와 응답 상태 코드가 200일 때 다른 본문으로 응답을 반환할 수 있습니다.
예를 들어 보겠습니다.
// For the 200 response, a copy of the updated object: { "id": 123, "text": "The updated text" } // For the 400 response, a list of validation errors: { "errors": [ "The updated text exceeds the maximum allowed number of characters." ] }
이를 염두에 두고 문제 설명으로 돌아가겠습니다. 작성 중인 HTTP 상태 코드에 따라 TypeScript가 내가 다루고 있는 본문을 알려줄 수 있는 이 PATCH 요청을 수행하는 함수를 어떻게 입력할 수 있습니까? 암호? 대답: 유창한 구문(빌더 구문, 연결 구문)을 사용하여 유형을 축적합니다.
솔루션 구축
이전 유형을 기반으로 하는 유형을 정의하는 것부터 시작하겠습니다.
export type AccumType<t newt> = T | NewT; </t>
매우 간단합니다. T와 NewT 유형이 주어지면 이를 결합하여 새로운 유형을 형성합니다. 이 새로운 유형을 AccumType에서 다시 T로 사용하면 또 다른 새로운 유형을 축적할 수 있습니다. 그러나 이 작업을 손으로 수행하는 것은 좋지 않습니다. 솔루션의 또 다른 핵심 요소인 Fluent 구문을 소개하겠습니다.
유창한 구문
메서드가 항상 자신(또는 자신의 복사본)을 반환하는 클래스 X의 개체가 있는 경우 메서드 호출을 차례로 연결할 수 있습니다. 이는 유창한 구문 또는 연결 구문입니다.
이를 수행하는 간단한 클래스를 작성해 보겠습니다.
export class NamePending<t> { accumulate<newt>() { return this as NamePending<accumtype newt>>; } } // Now you can use it like this: const x = new NamePending(); // x is of type NamePending. const y = x.accumulate // y is of type NamePending. </accumtype></newt></t>
유레카! 유창한 구문과 우리가 작성한 유형을 성공적으로 결합하여 데이터 유형을 단일 유형으로 축적하기 시작했습니다!
명확하지 않은 경우 원하는 유형이 누적될 때까지(x.accumulate().accumulate()… 완료될 때까지) 운동을 계속할 수 있습니다.
다 좋은데 이 초간단 유형은 HTTP 상태 코드를 해당 본문 유형에 묶지 않습니다.
우리가 가지고 있는 것을 개선하기
우리가 원하는 것은 유형 축소 기능이 시작될 수 있도록 TypeScript에 충분한 정보를 제공하는 것입니다. 이를 위해 원래 문제와 관련된 코드를 얻는 데 필요한 작업을 수행해 보겠습니다(HTTP 응답 본문을 -상태 코드 기준).
먼저 AccumType의 이름을 바꾸고 진화시킵니다. 아래 코드는 반복 진행 과정을 보여줍니다.
// Iteration 1. export type FetchResult<t newt> = T | NewT; // Iteration 2. export type FetchResponse<tstatus extends number tbody> = { ok: boolean; status: TStatus; statusText: string; body: TBody }; export type FetchResult<t tstatus extends number newt> = T | FetchResponse<tstatus newt>; //Makes sense to rename NewT to TBody. </tstatus></t></tstatus></t>
이 시점에서 저는 다음과 같은 사실을 깨달았습니다. 상태 코드는 유한합니다. 상태 코드를 찾아 유형을 정의하고 해당 유형을 사용하여 유형 매개변수 TStatus를 제한할 수 있다는 것입니다.
// Iteration 3. export type OkStatusCode = 200 | 201 | 202 | ...; export type ClientErrorStatusCode = 400 | 401 | 403 | ...; export type ServerErrorStatusCode = 500 | 501 | 502 | ...; export type StatusCode = OkStatusCode | ClientErrorStatusCode | ServerErrorStatusCode; export type NonOkStatusCode = Exclude<statuscode okstatuscode>; export type FetchResponse<tstatus extends statuscode tbody> = { ok: TStatus extends OkStatusCode ? true : false; status: TStatus; statusText: string; body: TBody }; export type FetchResult<t tstatus extends statuscode tbody> = T | FetchResponse<tstatus tbody>; </tstatus></t></tstatus></statuscode>
우리는 정말 아름다운 일련의 유형에 도달했습니다. ok 또는 status 속성의 조건을 기반으로 분기(if 문 작성)함으로써 TypeScript의 유형 축소 기능이 시작됩니다! 믿을 수 없다면 수업 부분을 작성하고 시도해 보세요.
export class DrFetch<t> { for<tstatus extends statuscode tbody>() { return this as DrFetch<fetchresult tstatus tbody>>; } } </fetchresult></tstatus></t>
시험해 보세요:
// For the 200 response, a copy of the updated object: { "id": 123, "text": "The updated text" } // For the 400 response, a list of validation errors: { "errors": [ "The updated text exceeds the maximum allowed number of characters." ] }
이제 상태 속성의 ok 속성을 기반으로 분기 시 유형 축소가 몸체의 모양을 올바르게 예측할 수 있는 이유가 명확해졌습니다.
그러나 문제가 있습니다. 클래스가 인스턴스화될 때 클래스의 초기 유형이 위의 주석 블록에 표시되어 있습니다. 저는 이렇게 해결했습니다:
export type AccumType<t newt> = T | NewT; </t>
이 작은 변화로 초기 타이핑이 사실상 제외되어 이제 영업을 시작하게 되었습니다!
이제 다음과 같은 코드를 작성할 수 있으며 Intellisense는 100% 정확합니다.
export class NamePending<t> { accumulate<newt>() { return this as NamePending<accumtype newt>>; } } // Now you can use it like this: const x = new NamePending(); // x is of type NamePending. const y = x.accumulate // y is of type NamePending. </accumtype></newt></t>
ok 속성을 쿼리할 때도 유형 축소가 작동합니다.
당신이 눈치 채지 못했다면, 우리는 오류를 던지지 않음으로써 훨씬 더 나은 코드를 작성할 수 있었습니다. 내 전문적인 경험에 따르면 axios도 틀리고, ky도 틀리고, 같은 작업을 수행하는 다른 가져오기 도우미도 틀립니다.
결론
TypeScript는 정말 재미있습니다. TypeScript와 유창한 구문을 결합함으로써 우리는 필요한 만큼 많은 유형을 축적할 수 있으므로 반복해서 디버깅한 후가 아니라 첫날부터 더 정확하고 명확한 코드를 작성할 수 있습니다. 이 기술은 성공적인 것으로 입증되었으며 누구나 시도해 볼 수 있습니다. dr-fetch를 설치하고 테스트해 보세요.
// Iteration 1. export type FetchResult<t newt> = T | NewT; // Iteration 2. export type FetchResponse<tstatus extends number tbody> = { ok: boolean; status: TStatus; statusText: string; body: TBody }; export type FetchResult<t tstatus extends number newt> = T | FetchResponse<tstatus newt>; //Makes sense to rename NewT to TBody. </tstatus></t></tstatus></t>
더욱 복잡한 패키지
또한 더 이상 사용되지 않는 .env 파일과 dotenv를 완전히 제거하는 것을 목표로 하는 패키지인 wj-config도 만들었습니다. 이 패키지는 여기서 설명하는 TypeScript 트릭도 사용하지만 유형을 |가 아닌 &로 결합합니다. 한번 사용해 보고 싶다면 v3.0.0-beta.1을 설치하세요. 그러나 타이핑은 훨씬 더 복잡합니다. wj-config 이후 dr-fetch를 만드는 것은 공원 산책이었습니다.
재미있는 것: 밖에 무엇이 있나요?
가져오기 관련 패키지에 있는 몇 가지 오류를 살펴보겠습니다.
동형 가져오기
README에서 다음 내용을 확인할 수 있습니다.
// Iteration 3. export type OkStatusCode = 200 | 201 | 202 | ...; export type ClientErrorStatusCode = 400 | 401 | 403 | ...; export type ServerErrorStatusCode = 500 | 501 | 502 | ...; export type StatusCode = OkStatusCode | ClientErrorStatusCode | ServerErrorStatusCode; export type NonOkStatusCode = Exclude<statuscode okstatuscode>; export type FetchResponse<tstatus extends statuscode tbody> = { ok: TStatus extends OkStatusCode ? true : false; status: TStatus; statusText: string; body: TBody }; export type FetchResult<t tstatus extends statuscode tbody> = T | FetchResponse<tstatus tbody>; </tstatus></t></tstatus></statuscode>
“서버 응답이 좋지 않습니다”?? 아니요. "서버가 귀하의 요청이 잘못되었다고 말합니다." 네, 던지는 부분 자체가 형편없습니다.
ts-fetch
이 아이디어는 맞지만 안타깝게도 OK와 OK가 아닌 응답만 입력할 수 있습니다(최대 2가지 유형).
케이
제가 가장 비판한 패키지 중 하나는 다음 예를 보여줍니다.
export class DrFetch<t> { for<tstatus extends statuscode tbody>() { return this as DrFetch<fetchresult tstatus tbody>>; } } </fetchresult></tstatus></t>
이것은 아주 후배 개발자가 쓸 내용입니다. 바로 행복한 길입니다. README에 따른 동등성:
const x = new DrFetch(); // Ok, having to write an empty type is inconvenient. const y = x .for() .for() ; /* y's type: DrFetch */
던지는 부분이 너무 안 좋아요. 왜 던지기 위해 가지를 치고, 나중에 잡으라고 강요하나요? 그것은 나에게 전혀 의미가 없습니다. 오류의 텍스트도 오해의 소지가 있습니다. 이는 "가져오기 오류"가 아닙니다. 가져오기가 작동했습니다. 답장 받았지, 그렇지? 당신은 단지 그것이 마음에 들지 않았을 뿐입니다… 왜냐하면 그것은 행복한 길이 아니기 때문입니다. 더 나은 표현은 "HTTP 요청 실패:"입니다. 실패한 것은 가져오기 작업이 아니라 요청 자체였습니다.
위 내용은 TypeScript를 사용하여 유형을 누적하는 방법: 가능한 모든 fetch() 결과 입력의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

JavaScript 프레임 워크의 힘은 개발 단순화, 사용자 경험 및 응용 프로그램 성능을 향상시키는 데 있습니다. 프레임 워크를 선택할 때 : 1. 프로젝트 규모와 복잡성, 2. 팀 경험, 3. 생태계 및 커뮤니티 지원.

서론 나는 당신이 이상하다는 것을 알고 있습니다. JavaScript, C 및 Browser는 정확히 무엇을해야합니까? 그들은 관련이없는 것처럼 보이지만 실제로는 현대 웹 개발에서 매우 중요한 역할을합니다. 오늘 우리는이 세 가지 사이의 밀접한 관계에 대해 논의 할 것입니다. 이 기사를 통해 브라우저에서 JavaScript가 어떻게 실행되는지, 브라우저 엔진의 C 역할 및 웹 페이지의 렌더링 및 상호 작용을 유도하기 위해 함께 작동하는 방법을 알게됩니다. 우리는 모두 JavaScript와 브라우저의 관계를 알고 있습니다. JavaScript는 프론트 엔드 개발의 핵심 언어입니다. 브라우저에서 직접 실행되므로 웹 페이지를 생생하고 흥미롭게 만듭니다. 왜 Javascr

Node.js는 크림 덕분에 효율적인 I/O에서 탁월합니다. 스트림은 메모리 오버로드를 피하고 큰 파일, 네트워크 작업 및 실시간 애플리케이션을위한 메모리 과부하를 피하기 위해 데이터를 점차적으로 처리합니다. 스트림을 TypeScript의 유형 안전과 결합하면 Powe가 생성됩니다

파이썬과 자바 스크립트 간의 성능과 효율성의 차이는 주로 다음과 같이 반영됩니다. 1) 해석 된 언어로서, 파이썬은 느리게 실행되지만 개발 효율이 높고 빠른 프로토 타입 개발에 적합합니다. 2) JavaScript는 브라우저의 단일 스레드로 제한되지만 멀티 스레딩 및 비동기 I/O는 Node.js의 성능을 향상시키는 데 사용될 수 있으며 실제 프로젝트에서는 이점이 있습니다.

JavaScript는 1995 년에 시작하여 Brandon Ike에 의해 만들어졌으며 언어를 C로 실현했습니다. 1.C Language는 JavaScript의 고성능 및 시스템 수준 프로그래밍 기능을 제공합니다. 2. JavaScript의 메모리 관리 및 성능 최적화는 C 언어에 의존합니다. 3. C 언어의 크로스 플랫폼 기능은 자바 스크립트가 다른 운영 체제에서 효율적으로 실행하는 데 도움이됩니다.

JavaScript는 브라우저 및 Node.js 환경에서 실행되며 JavaScript 엔진을 사용하여 코드를 구문 분석하고 실행합니다. 1) 구문 분석 단계에서 초록 구문 트리 (AST)를 생성합니다. 2) 컴파일 단계에서 AST를 바이트 코드 또는 기계 코드로 변환합니다. 3) 실행 단계에서 컴파일 된 코드를 실행하십시오.

Python 및 JavaScript의 미래 추세에는 다음이 포함됩니다. 1. Python은 과학 컴퓨팅 분야에서의 위치를 통합하고 AI, 2. JavaScript는 웹 기술의 개발을 촉진하고, 3. 교차 플랫폼 개발이 핫한 주제가되고 4. 성능 최적화가 중점을 둘 것입니다. 둘 다 해당 분야에서 응용 프로그램 시나리오를 계속 확장하고 성능이 더 많은 혁신을 일으킬 것입니다.

개발 환경에서 Python과 JavaScript의 선택이 모두 중요합니다. 1) Python의 개발 환경에는 Pycharm, Jupyternotebook 및 Anaconda가 포함되어 있으며 데이터 과학 및 빠른 프로토 타이핑에 적합합니다. 2) JavaScript의 개발 환경에는 Node.js, VScode 및 Webpack이 포함되어 있으며 프론트 엔드 및 백엔드 개발에 적합합니다. 프로젝트 요구에 따라 올바른 도구를 선택하면 개발 효율성과 프로젝트 성공률이 향상 될 수 있습니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기

드림위버 CS6
시각적 웹 개발 도구

Dreamweaver Mac版
시각적 웹 개발 도구

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전
