การใช้งาน Generic type ใน TypeScript

13 Aug 2023,
Share: 
Cover image

สวัสดีครับในบทความนี้เราจะมาเรียนรู้การใช้งาน Generic Type ใน TypeScript กันครับ

สำหรับภาษาทางด้าน Programming ที่จะต้องระบุ Type หรือชนิดของข้อมูล อย่าง C#, Java, ฯลฯ รวมไปถึง TypeScript ด้วย ในทุกๆครั้งที่เราประกาศตัวแปรขึ้นมาใช้งาน เราจําเป็นต้องระบุ Type หรือชนิดของข้อมูลทุกครั้ง

Generic Type จะมีประโยชน์ในการณีที่เราต้องการสร้าง Function, Class, Method ฯลฯ ที่เป็น Dynamic type ที่ผู้ใช้งานสามารถระบุ Type ที่จะทํางานเข้าไปตอนใช้งานได้ เพื่อให้เข้าในการทํางานมากขึ้นมาดูตัวอย่างแบบง่ายๆดังนี้

function identity(arg: number): number {
  return arg;
}

ปกติเวลาเราสร้าง Function ขึ้นมาใช้งานเราจะสร้างแบบ Code ด้านบน ซึ่งจะเห็นว่า Type ของข้อมูลที่รับเข้ามาจะถูกกําหนดเป็น number เท่านั้น หมายความว่าถ้าเราจะไม่สามารถจะนำ Function นี้ไปใช้กับ Type อื่นๆได้เลย

ถ้าเราต้องการให้ Function นี้สามารถใช้งานกับ Type อื่นๆได้ตามที่ ผู้ใช้งานระบุ เราจึงใช้ Generic Type เข้ามาช่วย โดยสามารถเขียนได้ดังนี้

function identity<T>(arg: T): T {
  return arg;
}

// สามารถใช้งานได้แบบนี้
const a = identity<string>('My string'); // a จะมี Type เป็น string
const b = identity('My string'); // b จะมี Type เป็น string
const c = identity<number>(100); // c จะมี Type เป็น number
const d = identity(100); // d จะมี Type เป็น number

จากตัวอย่างด้านบน เราสามารถใช้ "" เพื่อบอกว่าเป็น Generic Type โดยที่เราสามารถใช้ “T” ไปกำหนด Type ตามจุดต่างๆของ function ได้เลย ซึ่ง Code ด้านบน “T” ถูกกำหนดให้กับ Parameter ที่รับเข้ามา และ Type ของข้อมูลที่จะ Return ออกจาก Funvtion นี้ หมายความว่า Type ของข้อมูลที่ส่งเข้ามาทาง Parameter ของ Funvtion นี้จะต้องเป็น Type เดียวกันกับข้อมูลที่ Return ออกไป

Note: “T” สามารถเปลี่ยนเป็น Wording อื่นๆได้ ไม่จําเป็นต้องเป็น “T” เพียงอย่างเดียว

นอกเหนือจากนี้คุณสามารถเปลี่ยน “identity” Function ด้านบนไปเป็น Interface ได้ตามตัวอย่างนี้ครับ

interface GenericIdentityFn {
  <Type>(arg: Type): Type;
}

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: GenericIdentityFn = identity;

Generic Class

Generic Class ก็ใช้งานคือระบุไว้ใน ”<>” เช่นเดียวกันครับ มาดูตัวอย่างกันดังนี้

class GenericNumber<NumType> {
  zeroValue: NumType;
  add: (x: NumType, y: NumType) => NumType;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
  return x + y;
};

console.log(myGenericNumber.add(myGenericNumber.zeroValue, 100));

// More Example

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = '0';
stringNumeric.add = function (x, y) {
  const numX = +x; // Convert string to number
  const numY = +y; // Convert string to number
  return numX + numY;
};

console.log(stringNumeric.add(stringNumeric.zeroValue, '100'));

จากตัวอย่างด้านบน เราสามารถสร้าง Class ที่เป็น Generic Type ซึ่งจะสามารถทํางานกับ Type อื่นๆ ได้ตามที่ผู้ใช้งาน Class กําหนด

Generic Constraints

สําหรับการทํางานบางอย่างเราอาจจะต้องการที่จะระบุลงลึกไปอีกว่า Class หรือ function ที่เราจะสร้างขึ้นมานั้นจะต้องการ Type เป็นแบบใดยกตัวอย่างเช่น ถ้าเราต้องการสร้าง Funvtion ที่เอาไว้หา Length เราก็สามารถระบุไปแบบนี้ได้ครับ

interface Lengthwise {
  length: number;
}

function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
  console.log(arg.length); // Now we know it has a .length property, so no more error
  return arg;
}

// ตอนใช้งานจะรับเฉพาะ Paramiter type ที่มี property เป็น "length"
loggingIdentity({ length: 10, value: 3 }); // No Error
loggingIdentity('my string'); // No Error
loggingIdentity(100); // Error เพราะว่า type number ไม่มี property length

Using Type Parameters in Generic Constraints

เราสามารใช้ Type Parameters ใน Generic Constraints ตัวอย่างเช่นถ้าเราต้องการจะให้แน่ใจว่า ผู้ที่นํา Class หรือ Function ไปใช้งานจะระบุ propery หรือค่าบางอย่างมาถูกต้อง มาดูตัวอย่างกันครับ

function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, 'a');
getProperty(x, 'm'); // Error เพราะ property "m" ไม่มีใน x

Using Class Types in Generics

เราสามารถกำหนด Class type ใน Generic ได้ ตามตัวอย่างนี้ครับ

class BeeKeeper {
  hasMask: boolean = true;
}

class ZooKeeper {
  nametag: string = 'Mikle';
}

class Animal {
  numLegs: number = 4;
}

class Bee extends Animal {
  numLegs = 6;
  keeper: BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
  keeper: ZooKeeper = new ZooKeeper();
}

function createInstance<A extends Animal>(c: new () => A): A {
  return new c();
}

createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;

Suggestion blogs

เหรียญ 20 บาท 100 ปีกรมทางหลวง พ.ศ.2555

100 ปีกรมทางหลวง พ.ศ.2555คำอธิบายด้านหน้ากลางเหรียญมีพระบรมรูปพระบาทสมเด็จพระมงกุฏเกล้าเจ้าอยู่หัว ทรงฉลองพระองค์ชุดสากล ภายในวงขอบเหรียญเบื้องล่างมีข้อความว่า "พระบาทสมเด็จพระปรเมนทรมหาวชิราวุธ พระมงกุฏเกล้าเจ้าอยู่หัว"

How to send a file from remote URL in Node.js Express app

ใน nodejs express ถ้าต้องการ Response file จาก url อื่นๆ ตัวอย่างเช่น เรามี url "https://www.mydomain1.com/bg" แต่เราต้องการให้ เมื่อ Client เรียก url ดังกล่าวแล้ว ให้ไปนําข้อมูลจาก url "https://www.mydomain2.com/bg.jpg" ตอบกับไปให้ Client เราสามารทําได้ตามตัวอย่างดังนี้ครับ

ใช้ Docker Compose กับ Docker Swarm

สวัสดีครับจากบทความตอนที่แล้ว "เริ่มต้นใช้ Docker Swarm" เราได้เรียนรู้พื้นฐานการใช้งาน Docker Swarm กันไปแล้ว ในบทความนี้เราจะมาต่อยอดโดยนํา Docker Compose มาใช้ใน Docker Swarm เพราะในงานจริงเราจะได้ทํางานได้ง่ายและสะดวกขึ้น ก่อนที่จะอ่านบทความนี้ควรจะต้องมีความรู้ในเรื่องของ Docker Swarm และ Docker Compose ก่อน กลับไปอ่านได้ที่นี่


Copyright © 2019 - 2026 thiti.dev |  v1.61.0 |  Privacy policy | 

Build with ❤️ and Astro.

Github profile   Linkedin profile   Instagram   X profile   Nostr   Youtube channel   Telegram   Email contact   วงแหวนเว็บ