มีอะไรใหม่ใน TypeScript 5.0: Declarators, Const Type, Enums Improvement, Speed ​​และอีกมากมาย!

เผยแพร่แล้ว: 2023-04-15

TypeScript 5.0 เปิดตัวอย่างเป็นทางการเมื่อวันที่ 16 มีนาคม 2023 และตอนนี้ทุกคนสามารถใช้งานได้แล้ว รุ่นนี้แนะนำคุณสมบัติใหม่มากมายโดยมีจุดประสงค์เพื่อทำให้ TypeScript เล็กลง เรียบง่ายขึ้น และรวดเร็วขึ้น

รีลีสใหม่นี้ปรับปรุงตัวตกแต่งให้ทันสมัยสำหรับการปรับแต่งคลาส ทำให้สามารถปรับแต่งคลาสและสมาชิกในแบบที่นำกลับมาใช้ใหม่ได้ นักพัฒนาสามารถเพิ่มตัวแก้ไข const ให้กับการประกาศพารามิเตอร์ประเภทได้ ทำให้การอนุมานแบบ const เป็นค่าเริ่มต้น รีลีสใหม่ยังทำให้ enums union enums ทั้งหมด ทำให้โครงสร้างโค้ดง่ายขึ้น และเพิ่มความเร็วให้กับประสบการณ์ TypeScript

ในบทความนี้ คุณจะสำรวจการเปลี่ยนแปลงที่แนะนำใน TypeScript 5.0 โดยให้ข้อมูลเชิงลึกเกี่ยวกับคุณสมบัติและความสามารถใหม่ๆ

เริ่มต้นใช้งาน TypeScript 5.0

TypeScript เป็นคอมไพเลอร์อย่างเป็นทางการที่คุณสามารถติดตั้งในโครงการของคุณโดยใช้ npm หากคุณต้องการเริ่มใช้ TypeScript 5.0 ในโปรเจ็กต์ คุณสามารถเรียกใช้คำสั่งต่อไปนี้ในไดเร็กทอรีของโปรเจ็กต์:

 npm install -D typescript

ซึ่งจะติดตั้งคอมไพเลอร์ในไดเร็กทอรี node_modules ซึ่งตอนนี้คุณสามารถเรียกใช้ด้วยคำสั่ง npx tsc

คุณยังสามารถดูคำแนะนำเกี่ยวกับการใช้ TypeScript เวอร์ชันใหม่ใน Visual Studio Code ได้ในเอกสารประกอบนี้

ICYMI: TypeScript 5.0 มาแล้ว! สำรวจการอัปเดตที่น่าตื่นเต้น เช่น Declarators, Const Type และ Enums ที่ได้รับการปรับปรุงในคู่มือนี้ คลิกเพื่อทวีต

มีอะไรใหม่ใน TypeScript 5.0

ในบทความนี้ เรามาสำรวจการอัปเดตหลัก 5 รายการที่แนะนำใน TypeScript คุณสมบัติเหล่านี้รวมถึง:

มัณฑนากรที่ทันสมัย

Decorator ใช้งาน TypeScript มาระยะหนึ่งแล้วภายใต้แฟล็กทดลอง แต่รีลีสใหม่ทำให้เร็วขึ้นด้วยข้อเสนอ ECMAScript ซึ่งตอนนี้อยู่ในสเตจที่ 3 ซึ่งหมายความว่าอยู่ในสเตจที่เพิ่มลงใน TypeScript

ผู้ตกแต่งเป็นวิธีปรับแต่งพฤติกรรมของชั้นเรียนและสมาชิกด้วยวิธีที่นำมาใช้ซ้ำได้ ตัวอย่างเช่น ถ้าคุณมีคลาสที่มีสองเมธอด greet และ getAge :

 class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } greet() { console.log(`Hello, my name is ${this.name}.`); } getAge() { console.log(`I am ${this.age} years old.`); } } const p = new Person('Ron', 30); p.greet(); p.getAge();

ในกรณีการใช้งานจริง คลาสนี้ควรมีเมธอดที่ซับซ้อนกว่านี้ซึ่งจัดการกับลอจิก async บางอย่างและมีผลข้างเคียง ฯลฯ ซึ่งคุณต้องการโยนการเรียก console.log เพื่อช่วยดีบักเมธอด

 class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } greet() { console.log('LOG: Method Execution Starts.'); console.log(`Hello, my name is ${this.name}.`); console.log('LOG: Method Execution Ends.'); } getAge() { console.log('LOG: Method Execution Starts.'); console.log(`I am ${this.age} years old.`); console.log('Method Execution Ends.'); } } const p = new Person('Ron', 30); p.greet(); p.getAge();

นี่เป็นรูปแบบที่เกิดขึ้นบ่อยและสะดวกที่จะมีวิธีแก้ปัญหาสำหรับทุกวิธี

นี่คือจุดที่นักตกแต่งเข้ามาเล่น เราสามารถกำหนดฟังก์ชั่นชื่อ debugMethod ที่ปรากฏดังนี้

 function debugMethod(originalMethod: any, context: any) { function replacementMethod(this: any, ...args: any[]) { console.log('Method Execution Starts.'); const result = originalMethod.call(this, ...args); console.log('Method Execution Ends.'); return result; } return replacementMethod; }

ในโค้ดด้านบน debugMethod ใช้เมธอดเดิม ( originalMethod ) และส่งคืนฟังก์ชันที่ทำสิ่งต่อไปนี้:

  1. บันทึกข้อความ “เริ่มดำเนินการตามวิธี”
  2. ผ่านวิธีการดั้งเดิมและอาร์กิวเมนต์ทั้งหมด (รวมถึงสิ่งนี้)
  3. บันทึกข้อความ “วิธีดำเนินการสิ้นสุด”
  4. คืนค่าวิธีการเดิมที่ส่งคืน

โดยการใช้ตัวตกแต่ง คุณสามารถใช้ debugMethod กับเมธอดของคุณตามที่แสดงในโค้ดด้านล่าง:

 class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } @debugMethod greet() { console.log(`Hello, my name is ${this.name}.`); } @debugMethod getAge() { console.log(`I am ${this.age} years old.`); } } const p = new Person('Ron', 30); p.greet(); p.getAge();

สิ่งนี้จะแสดงผลต่อไปนี้:

 LOG: Entering method. Hello, my name is Ron. LOG: Exiting method. LOG: Entering method. I am 30 years old. LOG: Exiting method.

เมื่อกำหนดฟังก์ชันมัณฑนากร ( debugMethod ) พารามิเตอร์ที่สองจะถูกส่งผ่านเรียกว่า context (เป็นวัตถุบริบท — มีข้อมูลที่เป็นประโยชน์เกี่ยวกับวิธีการประกาศเมธอดการตกแต่งและชื่อของเมธอดด้วย) คุณสามารถอัปเดต debugMethod ของคุณเพื่อรับชื่อเมธอดจากวัตถุ context :

 function debugMethod( originalMethod: any, context: ClassMethodDecoratorContext ) { const methodName = String(context.name); function replacementMethod(this: any, ...args: any[]) { console.log(`'${methodName}' Execution Starts.`); const result = originalMethod.call(this, ...args); console.log(`'${methodName}' Execution Ends.`); return result; } return replacementMethod; }

เมื่อคุณเรียกใช้โค้ด เอาต์พุตจะแสดงชื่อของแต่ละวิธีที่ตกแต่งด้วยตัวตกแต่ง debugMethod :

 'greet' Execution Starts. Hello, my name is Ron. 'greet' Execution Ends. 'getAge' Execution Starts. I am 30 years old. 'getAge' Execution Ends.

มีมากกว่าที่คุณสามารถทำได้ด้วยมัณฑนากร อย่าลังเลที่จะตรวจสอบคำขอดึงต้นฉบับสำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้ตัวตกแต่งใน TypeScript

แนะนำพารามิเตอร์ประเภท const

นี่เป็นอีกหนึ่งรุ่นใหญ่ที่ให้เครื่องมือใหม่กับคุณเพื่อปรับปรุงการอนุมานที่คุณได้รับเมื่อคุณเรียกใช้ฟังก์ชัน ตามค่าเริ่มต้น เมื่อคุณประกาศค่าด้วย const TypeScript จะอนุมานประเภทและไม่ใช่ค่าตามตัวอักษร:

 // Inferred type: string[] const names = ['John', 'Jake', 'Jack'];

จนถึงตอนนี้ เพื่อให้ได้ข้อสรุปที่ต้องการ คุณต้องใช้การยืนยัน const โดยเพิ่ม "as const":

 // Inferred type: readonly ["John", "Jake", "Jack"] const names = ['John', 'Jake', 'Jack'] as const;

เมื่อคุณเรียกใช้ฟังก์ชัน มันจะคล้ายกัน ในโค้ดด้านล่าง ประเภท ประเทศ ที่อนุมานคือ string[] :

 type HasCountries = { countries: readonly string[] }; function getCountriesExactly(arg: T): T['countries'] { return arg.countries; } // Inferred type: string[] const countries = getCountriesExactly({ countries: ['USA', 'Canada', 'India'] });

คุณอาจต้องการประเภทที่เฉพาะเจาะจงมากขึ้น ซึ่งวิธีหนึ่งในการแก้ไขก่อนหน้านี้คือการเพิ่ม as const ยืนยัน:

 // Inferred type: readonly ["USA", "Canada", "India"] const names = getNamesExactly({ countries: ['USA', 'Canada', 'India'] } as const);

สิ่งนี้สามารถจดจำและนำไปใช้ได้ยาก อย่างไรก็ตาม TypeScript 5.0 นำเสนอคุณสมบัติใหม่ที่คุณสามารถเพิ่มตัวแก้ไข const ในการประกาศพารามิเตอร์ประเภท ซึ่งจะใช้การอนุมานแบบ const เป็นค่าเริ่มต้นโดยอัตโนมัติ

 type HasCountries = { countries: readonly string[] }; function getNamesExactly(arg: T): T['countries'] { return arg.countries; } // Inferred type: readonly ["USA", "Canada", "India"] const names = getNamesExactly({ countries: ['USA', 'Canada', 'India'] });

การใช้พารามิเตอร์ประเภท const ช่วยให้นักพัฒนาสามารถแสดงเจตนาได้ชัดเจนยิ่งขึ้นในโค้ดของตน หากตั้งใจให้ตัวแปรคงที่และไม่เปลี่ยนแปลง การใช้พารามิเตอร์ประเภท const จะทำให้แน่ใจได้ว่าตัวแปรนั้นจะไม่เปลี่ยนแปลงโดยไม่ตั้งใจ

คุณสามารถตรวจสอบคำขอดึงต้นฉบับสำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำงานของพารามิเตอร์ประเภท const ใน TypeScript

การปรับปรุง Enums

Enums ใน TypeScript เป็นโครงสร้างที่มีประสิทธิภาพซึ่งช่วยให้นักพัฒนาสามารถกำหนดชุดของค่าคงที่ที่มีชื่อได้ ใน TypeScript 5.0 มีการปรับปรุง enums เพื่อให้มีความยืดหยุ่นและมีประโยชน์มากยิ่งขึ้น

ตัวอย่างเช่น หากคุณมี enum ต่อไปนี้ที่ส่งผ่านไปยังฟังก์ชัน:

 enum Color { Red, Green, Blue, } function getColorName(colorLevel: Color) { return colorLevel; } console.log(getColorName(1));

ก่อนเปิดตัว TypeScript 5.0 คุณสามารถส่งหมายเลขระดับผิดได้ และจะไม่มีข้อผิดพลาดเกิดขึ้น แต่ด้วยการเปิดตัว TypeScript 5.0 จะทำให้เกิดข้อผิดพลาดทันที

นอกจากนี้ รีลีสใหม่ยังทำให้ enums ทั้งหมดเป็น union enums โดยการสร้างประเภทเฉพาะสำหรับแต่ละสมาชิกที่คำนวณ การปรับปรุงนี้ทำให้ enums ทั้งหมดแคบลงและการอ้างอิงสมาชิกเป็นประเภท:

 enum Color { Red, Purple, Orange, Green, Blue, Black, White, } type PrimaryColor = Color.Red | Color.Green | Color.Blue; function isPrimaryColor(c: Color): c is PrimaryColor { return c === Color.Red || c === Color.Green || c === Color.Blue; } console.log(isPrimaryColor(Color.White)); // Outputs: false console.log(isPrimaryColor(Color.Red)); // Outputs: true

การปรับปรุงประสิทธิภาพของ TypeScript 5.0

TypeScript 5.0 มีการเปลี่ยนแปลงที่สำคัญมากมายในโครงสร้างโค้ด โครงสร้างข้อมูล และส่วนขยายของอัลกอริทึม สิ่งนี้ช่วยปรับปรุงประสบการณ์ TypeScript ทั้งหมด ตั้งแต่การติดตั้งจนถึงการดำเนินการ ทำให้เร็วขึ้นและมีประสิทธิภาพมากขึ้น

ตัวอย่างเช่น ความแตกต่างระหว่างขนาดแพ็คเกจของ TypeScript 5.0 และ 4.9 นั้นค่อนข้างน่าประทับใจ

เมื่อเร็วๆ นี้ TypeScript ถูกย้ายจากเนมสเปซไปยังโมดูล ทำให้สามารถใช้ประโยชน์จากเครื่องมือสร้างสมัยใหม่ที่สามารถดำเนินการปรับให้เหมาะสม เช่น การยกขอบเขต นอกจากนี้ การลบโค้ดที่เลิกใช้แล้วบางส่วนได้ลดขนาดแพ็คเกจ 63.8 MB ของ TypeScript 4.9 ประมาณ 26.4 MB

ขนาดแพ็คเกจ TypeScript
ขนาดแพ็คเกจ TypeScript

ต่อไปนี้เป็นชัยชนะที่น่าสนใจอีกเล็กน้อยในด้านความเร็วและขนาดระหว่าง TypeScript 5.0 และ 4.9:

สถานการณ์ เวลาหรือขนาดที่สัมพันธ์กับ TS 4.9
เวลาในการสร้างวัสดุ-UI 90%
เวลาเริ่มต้นของ TypeScript Compiler 89%
เวลาสร้างนักเขียนบทละคร 88%
TypeScript Compiler เวลาสร้างตัวเอง 87%
เวลาในการสร้างเว็บ Outlook 82%
VS เวลาในการสร้างโค้ด 80%
typescript npm ขนาดแพ็คเกจ 59%

ความละเอียดของ Bundler เพื่อความละเอียดของโมดูลที่ดีขึ้น

เมื่อคุณเขียนคำสั่งนำเข้าใน TypeScript คอมไพลเลอร์จำเป็นต้องรู้ว่าการนำเข้านั้นอ้างอิงถึงอะไร ทำสิ่งนี้โดยใช้ความละเอียดของโมดูล ตัวอย่างเช่น เมื่อคุณเขียน import { a } from "moduleA" คอมไพเลอร์จำเป็นต้องทราบคำจำกัดความของ a ใน moduleA เพื่อตรวจสอบการใช้งาน

ใน TypeScript 4.7 มีการเพิ่มตัวเลือกใหม่สองตัวเลือกสำหรับการตั้งค่า --module และ moduleResolution : node16 และ nodenext

จุดประสงค์ของตัวเลือกเหล่านี้คือเพื่อแสดงกฎการค้นหาที่ถูกต้องแม่นยำยิ่งขึ้นสำหรับโมดูล ECMAScript ใน Node.js อย่างไรก็ตาม โหมดนี้มีข้อจำกัดหลายประการที่ไม่ได้บังคับใช้โดยเครื่องมืออื่นๆ

ตัวอย่างเช่น ในโมดูล ECMAScript ใน Node.js การนำเข้าที่เกี่ยวข้องใดๆ จะต้องมีนามสกุลไฟล์เพื่อให้ทำงานได้อย่างถูกต้อง:

 import * as utils from "./utils"; // Wrong import * as utils from "./utils.mjs"; // Correct

TypeScript ได้เปิดตัวกลยุทธ์ใหม่ที่เรียกว่า “moduleResolution Bundler” กลยุทธ์นี้สามารถนำไปใช้ได้โดยการเพิ่มโค้ดต่อไปนี้ในส่วน "compilerOptions" ของไฟล์การกำหนดค่า TypeScript ของคุณ:

 { "compilerOptions": { "target": "esnext", "moduleResolution": "bundler" } }

กลยุทธ์ใหม่นี้เหมาะสำหรับผู้ที่ใช้ Bundler สมัยใหม่ เช่น Vite, esbuild, swc, Webpack, Parcel และอื่นๆ ที่ใช้กลยุทธ์การค้นหาแบบผสมผสาน

คุณสามารถตรวจสอบคำขอดึงต้นฉบับและการใช้งานสำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำงานของ moduleResolution bundler ใน TypeScript

การเลิกใช้

TypeScript 5.0 มาพร้อมกับค่าเสื่อมราคา รวมถึงข้อกำหนดรันไทม์ การเปลี่ยนแปลง lib.d.ts และการเปลี่ยนแปลงการทำลาย API

  1. ข้อกำหนดรันไทม์: ขณะนี้ TypeScript กำหนดเป้าหมายไปที่ ECMAScript 2018 และแพ็คเกจตั้งค่าความคาดหวังของกลไกขั้นต่ำที่ 12.20 ดังนั้น ผู้ใช้ Node.js ควรมีเวอร์ชันขั้นต่ำ 12.20 หรือใหม่กว่าเพื่อใช้ TypeScript 5.0
  2. การเปลี่ยนแปลง lib.d.ts: มีการเปลี่ยนแปลงบางอย่างเกี่ยวกับวิธีสร้างประเภทสำหรับ DOM ซึ่งอาจส่งผลต่อโค้ดที่มีอยู่ โดยเฉพาะอย่างยิ่ง คุณสมบัติบางอย่างได้ถูกแปลงจากตัวเลขเป็นประเภทตัวอักษรที่เป็นตัวเลข และคุณสมบัติและวิธีการสำหรับการจัดการเหตุการณ์การตัด คัดลอก และวางได้ถูกย้ายข้ามอินเทอร์เฟซ
  3. การเปลี่ยนแปลงการทำลาย API: อินเทอร์เฟซที่ไม่จำเป็นบางส่วนถูกลบออก และมีการปรับปรุงความถูกต้องบางอย่าง TypeScript 5.0 ได้ย้ายไปที่โมดูลแล้ว

TypeScript 5.0 ได้เลิกใช้การตั้งค่าบางอย่างและค่าที่สอดคล้องกัน รวมถึง target: ES3 , out , noImplicitUseStrict , keyofStringsOnly , suppressExcessPropertyErrors , suppressImplicitAnyIndexErrors , noStrictGenericChecks , charset , importsNotUsedAsValues ​​และ preserveValueImports รวมถึงส่วนนำหน้าในการอ้างอิงโครงการ

แม้ว่าการกำหนดค่าเหล่านี้จะยังคงใช้งานได้จนถึง TypeScript 5.5 คำเตือนจะออกเพื่อแจ้งเตือนผู้ใช้ที่ยังคงใช้งานอยู่

TypeScript 5.0 ง่ายกว่า เร็วกว่า และเล็กกว่า! สำรวจการเปลี่ยนแปลงที่จะปฏิวัติเกมการเขียนโค้ดของคุณที่นี่ คลิกเพื่อทวีต

สรุป

ในบทความนี้ คุณได้เรียนรู้คุณลักษณะหลักและการปรับปรุงบางอย่างที่ TypeScript 5.0 นำมาใช้ เช่น การปรับปรุง enums ความละเอียดของ Bundler และพารามิเตอร์ประเภท Const พร้อมกับการปรับปรุงความเร็วและขนาด

หากคุณกำลังคิดเกี่ยวกับ TypeScript สำหรับโปรเจกต์ต่อไปของคุณ ลองใช้แอพพลิเคชั่นโฮสติ้งของ Kinsta ฟรี

ตอนนี้ถึงตาคุณแล้ว! คุณลักษณะหรือการปรับปรุงใดที่คุณพบว่าน่าสนใจที่สุดใน TypeScript 5.0 มีสาระสำคัญที่เราอาจมองข้ามไปหรือไม่? แจ้งให้เราทราบในความคิดเห็น.