javascript - กำหนดคลาสในโมดูล Typescript
ฉันกำลังเขียนโมดูล Typescript สำหรับไลบรารีภายนอก
นี่คือตัวอย่างของ index.d.ts ของฉัน
declare module 'my-external-library' {
export class MyComponent extends React.Component<MyComponentProps> {}
export class CustomClass {
constructor(
firstParam: string,
secondParam: string,
)
}
interface MyComponentProps {
config: string
customClass: CustomClass
text?: string
customFn?: (input: string) => boolean
}
}
สิ่งนี้ใช้งานได้ดี ยกเว้น customClass prop. Custom Class เป็นคลาสที่ต้องเป็นแบบนี้:
class customClass {
constructor(firstParam, secondParam) {
this.firstParam = firstParam
this.secondParam = secondParam
}
... all the methods you want
}
export default customClass
ในไฟล์แยกต่างหาก ฉันให้ props customClass กับ MyComponent แบบนี้:
import customClass from './customClass'
<MyComponent
config: "test"
customClass: customClass
/>
customClass จริง ๆ แล้วไม่ได้รับ “ประเภทตัวสร้าง” ที่ประกาศใน index.d.ts แต่คุณสมบัติอื่น ๆ ของคอมโพเนนต์ทำงานได้ดี ดังนั้น การนิยามคลาสที่ฉันสร้างมาถูกต้องหรือไม่? ฉันต้องส่งออกคลาสด้วยวิธีอื่นหรือไม่?
นี่คือ CodeSandbox: https://codesandbox.io/s/react-typescript-playground-forked-nrfk2
ขอบคุณสำหรับความช่วยเหลือใด ๆ โปรดให้อภัยความไม่มีประสบการณ์ของฉัน
คำตอบ #1
ฉันได้ทำการแยกและแก้ไข sandbox โค้ดของคุณ ลองดูสิ:
ตอนนี้ฉันจะอธิบายบางสิ่งเกี่ยวกับคลาสในไทป์สคริปต์ ซึ่งมันค่อนข้างสับสนจริงๆ
ส่วนหนึ่งเป็นเพราะว่าผู้คนใช้คำว่า "class" เพื่ออ้างถึงสิ่งที่แตกต่างกันในบริบทที่แตกต่างกัน เพื่อความกระจ่าง เรามาใช้คำที่ถูกต้องมากขึ้นกัน
ตัวสร้าง
MyPuppy มักถูกเรียกว่า "คลาส" แต่ในแง่ของ JS มันก็เป็น "ฟังก์ชันคอนสตรัคเตอร์" ด้วย ดังนั้นมาลองใช้คำว่า คอนสตรัคเตอร์ ตลอดการอภิปรายนี้กันเถอะ
// javascript
class MyPuppy {}
ตัวอย่าง
ตัวแปร puppy เป็น อินสแตนซ์ ของ MyPuppet
// javascript
const puppy = new MyPuppet()
ประเภทอินสแตนซ์ เทียบกับประเภทคอนสตรัคเตอร์
ใน TypeScript เมื่อคุณประกาศคลาสแบบด้านล่าง คุณจะ ประกาศโดยนัย ชนิดอินสแตนซ์ ที่มีชื่อเดียวกัน!
พฤติกรรมนี้ทำให้หลายคนสับสน โดยสรุป MyPuppy ในฐานะ ตัวแปร JS ถือว่าเป็น constructor ในขณะที่ MyPuppy ในฐานะ ตัวแปรประเภท TS จริงๆ แล้วถือว่าเป็น instance type
ตอนนี้เราจะอ้างอิงถึงประเภทของตัวสร้าง MyPuppy หรือที่เรียกว่า ประเภทตัวสร้าง อย่างไร? คุณควรใช้จริงๆ ว่า typeof MyPuppy.
// typescript
class MyPuppet {}
type MyPuppetInstance = MyPuppet
type MyPuppetConstructor = typeof MyPuppet
เราได้ทำการชี้แจงความหมายของคำแล้ว มาทำกรณีศึกษากันเถอะ
มีแนวคิดเกี่ยวกับ "ด้านอินสแตนซ์" และ "ด้านสแตติก" ของคลาส ซึ่งเคยถูกบันทึกไว้ในคู่มือ TS เก่า ๆ โดยพื้นฐานแล้ว "ด้านอินสแตนซ์" จะตรงกับ ประเภทอินสแตนซ์ และ "ด้านสแตติก" จะตรงกับ ประเภทคอนสตรักเตอร์
class MyPuppy {
static getSpecies(dog: MyPuppy) {
return dog.species
}
constructor(species: string) { this.species = species }
species: string
// [side note] above two lines can be combined as one:
// constructor(public species: string) {}
poop() { return '💩' }
}
type MyPuppetInstance = MyPuppet
type MyPuppetConstructor = typeof MyPuppet
var bar: MyPuppetConstructor = MyPuppy
var foo: MyPuppetInstance = new bar("shiba_inu")
โค้ดตัวอย่างด้านบนทำหลายอย่าง
- ประกาศ constructor ของ JS ที่ชื่อ
MyPuppy - ประกาศชนิด instance ของ TS
MyPuppyโดยนัย - ในด้าน "instance" ,
fooเป็น instance และมีคุณสมบัติspeciesและวิธีpoop. - ในด้าน "คงที่"
barเป็น ตัวสร้าง ซึ่งเป็น "ฟังก์ชันที่สามารถสร้างใหม่ได้" ซึ่งสามารถเรียกใช้งานได้เป็นnew bar("shiba_inu")และยังมีเมธอดคงที่getSpeciesอีกด้วย
ตอนนี้ในไฟล์ .d.ts เราจะประกาศประเภทข้างต้นอย่างไร? คุณสามารถใช้ได้ทั้งคีย์เวิร์ด interface หรือคีย์เวิร์ด type พวกมันเกือบจะไม่ต่างกันเลย
// index.d.ts
interface MyPuppyInstance {
species: string
poop(): string
}
interface MyPuppyConstructor {
new (species: string): MyPuppyInstance
getSpecies(dog: { species: string }): string
}
type MyPuppyInstance2 = {
species: string
poop(): string
}
type MyPuppyConstructor2 =
(new (species: string) => MyPuppyInstance)
& { getSpecies(dog: { species: string }): string }