مستودع تعريفات أنواع TypeScript عالية الجودة .
يمكنك أيضًا قراءة هذا التمهيد باللغات الأسبانية، 한국어، Русский، 简体中文، البرتغالية، الإيطالية، 日本語 والفرنسية!
رابط إلى دليل المشرف
لقد تغيرت الكتابة بالتأكيد مؤخرًا إلى pnpm
monorepo مناسب؛ قد ترغب في إعادة قراءة هذا المستند لإجراء تغييرات على تخطيط الحزم في هذا الريبو.
على أقل تقدير، قد ترغب في استخدام git clean -fdx
the repo (أو node ./scripts/clean-node-modules.js
على نظام التشغيل Windows) لتنظيف node_modules
وتشغيل pnpm install --filter .
لتثبيت جذر مساحة العمل. راجع المزيد من الأقسام لمزيد من المعلومات حول pnpm install
.
يتتبع هذا القسم سلامة المستودع وعملية النشر. قد يكون من المفيد للمساهمين الذين يواجهون أي مشكلات تتعلق بالعلاقات العامة والحزم الخاصة بهم.
إذا كان هناك أي شيء يبدو خاطئًا أو فشل أي مما سبق، فيرجى إخبارنا بذلك في قناة Definitely Typed على خادم TypeScript Community Discord.
راجع دليل TypeScript.
هذه هي الطريقة المفضلة. على سبيل المثال:
npm install --save-dev @types/node
لتثبيت الكتابة لوحدة محددة النطاق، قم بإزالة @
وأضف شرطة سفلية مزدوجة بعد النطاق. على سبيل المثال، لتثبيت الكتابة لـ @babel/preset-env
:
npm install --save-dev @types/babel__preset-env
يجب بعد ذلك تضمين الأنواع تلقائيًا بواسطة المترجم. قد تحتاج إلى إضافة مرجع types
إذا كنت لا تستخدم الوحدات النمطية:
/// <reference types="node" />
انظر المزيد في الكتيب.
بالنسبة لحزمة npm "foo"، ستكون الكتابة لها على "@types/foo".
إذا كانت الحزمة الخاصة بك تحتوي على أنواع محددة باستخدام مفتاح types
أو typings
في package.json
، فسيعرض سجل npm أن الحزمة تحتوي على روابط متاحة مثل:
يمكنك استنساخ المستودع بأكمله كالمعتاد، ولكنه كبير ويتضمن دليلاً ضخمًا لحزم النوع. سيستغرق هذا بعض الوقت للاستنساخ وقد يكون غير عملي بلا داع.
للحصول على استنساخ أكثر قابلية للإدارة يتضمن فقط حزم النوع ذات الصلة بك، يمكنك استخدام ميزات git- sparse-checkout
و-- --filter
. سيؤدي هذا إلى تقليل وقت الاستنساخ وتحسين أداء git.
️ يتطلب هذا الحد الأدنى من إصدار git 2.27.0، والذي من المحتمل أن يكون أحدث من الإصدار الافتراضي في معظم الأجهزة. تتوفر إجراءات أكثر تعقيدًا في الإصدارات الأقدم، ولكن لا يغطيها هذا الدليل.
git clone --sparse --filter=blob:none <forkedUrl>
--sparse
يقوم بتهيئة ملف السحب المتفرق بحيث يبدأ دليل العمل بالملفات الموجودة في جذر المستودع فقط.--filter=blob:none
سوف يقوم بتضمين كل سجل الالتزام ولكنه يستبعد الملفات، ويجلبها حسب الحاجة فقط.git sparse-checkout add types/<type> types/<dependency-type> ...
pnpm test <package to test>
. عندما تقوم بإجراء علاقات عامة لتحرير حزمة موجودة، يجب على dt-bot
الإشارة @ إلى مالكي الحزمة. إذا لم يكن الأمر كذلك، فيمكنك القيام بذلك بنفسك في التعليق المرتبط بالعلاقات العامة.
إذا كنت مؤلف المكتبة وكانت الحزمة الخاصة بك مكتوبة بلغة TypeScript، فقم بتجميع ملفات التصريح التي تم إنشاؤها في الحزمة الخاصة بك بدلاً من النشر إلى Definitely Typed. يمكنك أيضًا إنشاء ملفات تعريف من ملفات JavaScript، باستخدام JSDoc للتعليقات التوضيحية للنوع.
إذا كنت تقوم بإضافة أنواع لحزمة npm، فقم بإنشاء دليل بنفس الاسم. إذا كانت الحزمة التي تضيف أنواعًا لها ليست موجودة على npm، فتأكد من أن الاسم الذي تختاره لها لا يتعارض مع اسم الحزمة الموجودة على npm. (يمكنك استخدام npm info <my-package>
للتحقق من وجود الحزمة <my-package>
.)
يجب أن تحتوي الحزمة الخاصة بك على هذا الهيكل:
ملف | غاية |
---|---|
index.d.ts | يحتوي هذا على كتابات الحزمة. |
<my-package>-tests.ts | يحتوي هذا على نموذج التعليمات البرمجية الذي يختبر الكتابة. لا يعمل هذا الرمز، ولكن تم التحقق من نوعه. |
tsconfig.json | يتيح لك ذلك تشغيل tsc داخل الحزمة. |
.eslintrc.json | (نادرًا) مطلوب فقط لتعطيل قواعد الوبر المكتوبة لـ eslint. |
package.json | يحتوي على البيانات الوصفية للحزمة، بما في ذلك اسمها وإصدارها وتبعياتها. |
.npmignore | يحدد الملفات التي سيتم تضمينها في الحزمة. |
أنشئها عن طريق تشغيل npx dts-gen --dt --name <my-package> --template module
. شاهد جميع الخيارات في dts-gen.
إذا كان لديك ملفات .d.ts
إلى جانب index.d.ts
، فتأكد من الإشارة إليها إما في index.d.ts
أو في الاختبارات.
يقوم الأعضاء المكتوبون بالتأكيد بمراقبة العلاقات العامة الجديدة بشكل روتيني، مع الأخذ في الاعتبار أن عدد العلاقات العامة الأخرى قد يؤدي إلى إبطاء الأمور.
للحصول على حزمة أمثلة جيدة، راجع base64-js.
عندما تجمع الحزمة أنواعًا خاصة بها، يجب إزالة الأنواع من "الكتابة المحددة" لتجنب الالتباس.
يمكنك إزالته عن طريق تشغيل pnpm run not-needed <typingsPackageName> <asOfVersion> [<libraryName>]
.
<typingsPackageName>
: هذا هو اسم الدليل المراد حذفه.<asOfVersion>
: سيتم نشر كعب الروتين إلى @types/<typingsPackageName>
مع هذا الإصدار. يجب أن يكون أعلى من أي إصدار منشور حاليًا ويجب أن يكون إصدارًا من <libraryName>
على npm.<libraryName>
: اسم حزمة npm التي تحل محل الأنواع المكتوبة بالتأكيد. عادةً ما يكون هذا مطابقًا لـ <typingsPackageName>
، وفي هذه الحالة يمكنك حذفه. إذا لم يتم كتابة الحزمة مطلقًا، فلن تحتاج إلى إضافتها إلى notNeededPackages.json
.
اختبر تغييراتك عن طريق تشغيل pnpm test <package to test>
حيث يكون <package to test>
هو اسم الحزمة الخاصة بك. تحتاج إلى تشغيل هذا من دليل DefinitelyTyped لأن ملف package.jsons الفردي لا يحدد البرامج النصية للاختبار.
يستخدم هذا البرنامج النصي dtslint لتشغيل مترجم TypeScript على ملفات dts الخاصة بك.
بمجرد أن تصبح جميع التغييرات جاهزة، استخدم pnpm run test-all
لترى كيف تؤثر تغييراتك على الوحدات الأخرى.
attw
) الشيكات يتضمن dtslint تنسيق الوحدة النمطية وعمليات التحقق من تكوين package.json
من @arethetypeswrong/cli. يتم تشغيل الاختبارات فقط إذا كان من الممكن العثور على حزمة تنفيذ متوافقة مع SemVer-major على npm للمقارنة مع حزمة DefinitelyTyped. (يتم تخطي الحزم التي تم وضع علامة nonNpm
عليها في package.json
الخاصة بها.)
تفشل العديد من الحزم حاليًا في فحوصات attw
وتحتاج إلى الإصلاح. للسماح لنا بإحراز تقدم متزايد، لا تفشل اختبارات attw
الفاشلة في تشغيل dtslint
عندما تكون الحزمة مدرجة في failingPackages
في attw.json
، ولكن سيتم الإبلاغ عنها في مخرجات pnpm test my-package
. إذا قمت بإصلاح الحزمة، فقم بإزالتها من failingPackages
حتى تتمكن عمليات فحص attw
من بدء تشغيل dtslint
الفاشل.
جميع المشكلات التي أبلغت عنها attw
لها وثائق مرتبطة بالمخرجات. بعض القواعد الأساسية للمساعدة في تجنب المشاكل:
يجب أن تحتوي package.json
الموجودة في الحزمة DefinitelyTyped على حقول type
exports
المتطابقة إذا كانت حزمة التنفيذ تستخدمها في package.json
الخاصة بها. على سبيل المثال، إذا كانت package.json
التنفيذ.json تبدو كما يلي:
{
"name" : " my-package " ,
"version" : " 1.0.1 " ,
"type" : " module " ,
"main" : " dist/cjs/index.cjs " ,
"exports" : {
"." : {
"import" : " ./dist/esm/index.js " ,
"require" : " ./dist/cjs/index.cjs "
},
"./subpath" : {
"import" : " ./dist/esm/subpath.js " ,
"require" : " ./dist/cjs/subpath.cjs "
}
}
}
ثم يجب أن يبدو ملف DefinitelyTyped package.json
بالشكل التالي:
{
"name" : "@types/my-package" ,
"version" : "1.0.9999" ,
"type" : "module" ,
"types" : "index.d.ts" ,
"exports" : {
"." : {
"import" : "./index.d.ts" ,
"require" : "./index.d.cts"
} ,
"./subpath" : {
"import" : "./subpath.d.ts" ,
"require" : "./subpath.d.cts"
}
}
}
لاحظ أن كل مسار فرعي exports
ينعكس، وأن كل ملف JavaScript يحتوي على ملف تعريف مطابق بامتداد ملف مطابق - ملف .d.ts
أنواع ملف .js
، وليس ملف .mjs
أو .cjs
!
عندما تستخدم حزمة التنفيذ module.exports = ...
، يجب أن تستخدم حزمة DefinitelyTyped export =
، وليس export default
. (بدلاً من ذلك، إذا كان module.exports
مجرد كائن ذو خصائص مسماة، فيمكن لحزمة DefinitelyTyped استخدام سلسلة من عمليات التصدير المسماة.) العائق الأكثر شيوعًا لتصحيح هذه المشكلة هو الارتباك حول كيفية تصدير الأنواع بالإضافة إلى التصدير الأساسي. على سبيل المثال، افترض أن هذه الأنواع تستخدم بشكل غير صحيح export default
:
export interface Options {
// ...
}
export default function doSomething ( options : Options ) : void ;
تغيير الإعداد export default
إلى export =
يؤدي إلى حدوث خطأ:
export interface Options {
// ...
}
declare function doSomething ( options : Options ) : void ;
export = doSomething ;
// ^^^^^^^^^^^^^^^^^
// Error: An export assignment cannot be used in a module with other exported elements.
لإصلاح ذلك، انقل الأنواع داخل مساحة الاسم التي تحمل نفس اسم الوظيفة:
declare namespace doSomething {
export interface Options {
// ...
}
}
declare function doSomething ( options : doSomething . Options ) : void ;
export = doSomething ;
إذا كنت بحاجة إلى مساعدة في حل مشكلة ما، فيرجى سؤالها في قناة DefinitelyTyped على خادم TypeScript Community Discord.
إذا كنت تقوم بإضافة أنواع لحزمة npm، فقم بإنشاء دليل بنفس الاسم. إذا كانت الحزمة التي تضيف كتابات لها ليست على npm، فاضبط "nonNpm": true
في package.json
، وتأكد من أن الاسم الذي تختاره لها لا يتعارض مع اسم الحزمة على npm. (يمكنك استخدام npm info <my-package>
للتحقق من وجود الحزمة <my-package>
.)
في حالات نادرة، قد يتم ضبط nonNpm
على "conflict"
، مما يشير إلى وجود حزمة على npm بنفس الاسم، ولكن الأنواع تتعارض عمدًا مع تلك الحزمة. يمكن أن يكون هذا صحيحًا بالنسبة للحزم التي تحدد بيئة مثل @types/node
أو للحزم الوهمية مثل aws-lambda
. تجنب استخدام "conflict"
حيثما أمكن ذلك.
<my-package>-tests.ts
يجب أن يكون هناك ملف <my-package>-tests.ts
، والذي يعتبر ملف الاختبار الخاص بك، بالإضافة إلى أي ملفات *.ts
يتم استيرادها. إذا لم تشاهد أي ملفات اختبار في مجلد الوحدة، فقم بإنشاء <my-package>-tests.ts
. يتم استخدام هذه الملفات للتحقق من صحة واجهة برمجة التطبيقات المصدرة من ملفات *.d.ts
التي يتم شحنها كـ @types/<my-package>
. إنهم لا يشحنون أنفسهم.
يجب أن تتضمن التغييرات التي يتم إجراؤها على ملفات *.d.ts
تغييرًا مناظرًا في ملف *.ts
يوضح واجهة برمجة التطبيقات المستخدمة، حتى لا يقوم شخص ما بكسر التعليمات البرمجية التي تعتمد عليها عن طريق الخطأ. على سبيل المثال، هذا التغيير إلى دالة في ملف .d.ts
يضيف معلمة جديدة إلى دالة:
index.d.ts
:
- export function twoslash(body: string): string
+ export function twoslash(body: string, config?: { version: string }): string
<my-package>-tests.ts
:
import {twoslash} from "./"
// $ExpectType string
const result = twoslash("//")
+ // Handle options param
+ const resultWithOptions = twoslash("//", { version: "3.7" })
+ // When the param is incorrect
+ // @ts-expect-error
+ const resultWithOptions = twoslash("//", { })
إذا كنت تتساءل من أين تبدأ بكود الاختبار، فإن الأمثلة الموجودة في الملف التمهيدي للحزمة الأصلية هي مكان رائع للبدء.
يمكنك التحقق من صحة تغييراتك باستخدام npm test <package to test>
من جذر هذا الريبو، والذي يأخذ الملفات التي تم تغييرها في الاعتبار.
استخدم $ExpectType
للتأكيد على أن التعبير من نوع معين و @ts-expect-error
للتأكيد على أن هناك خطأ في الترجمة. أمثلة:
// $ExpectType void
f ( 1 ) ;
// @ts-expect-error
f ( "one" ) ;
لمزيد من التفاصيل، راجع الملف التمهيدي dtslint.
.eslintrc.json
إذا كانت هناك حاجة إلى تعطيل قاعدة الوبر لسبب ما، فقم بتعطيلها لسطر معين:
// eslint-disable-next-line no-const-enum
const enum Const {
One ,
}
const enum Enum { // eslint-disable-line no-const-enum
Two ,
}
لا يزال بإمكانك تعطيل القواعد باستخدام .eslintrc.json، لكن لا ينبغي ذلك في الحزم الجديدة. يؤدي تعطيل القواعد للحزمة بأكملها إلى زيادة صعوبة المراجعة.
tsconfig.json
يجب أن يكون لدى tsconfig.json
noImplicitAny
و noImplicitThis
و strictNullChecks
و strictFunctionTypes
مضبوطة على true
.
يمكنك تحرير tsconfig.json
لإضافة ملفات اختبار جديدة، أو لإضافة "target": "es6"
(مطلوب للوظائف غير المتزامنة)، أو للإضافة إلى "lib"
أو لإضافة خيار المترجم "jsx"
.
esModuleInterop
/ allowSyntheticDefaultImports
TL;DR: esModuleInterop
و allowSyntheticDefaultImports
غير مسموح بهما في tsconfig.json
.
تتيح هذه الخيارات كتابة استيراد افتراضي لتصدير CJS، ونمذجة قابلية التشغيل البيني المضمنة بين وحدات CJS وES في Node وفي بعض حزم JS:
// component.d.ts declare class Component { } // CJS export, modeling `module.exports = Component` in JS export = Component ; // index.d.ts // ESM default import, only allowed under 'esModuleInterop' or 'allowSyntheticDefaultExports' import Component from "./component" ;نظرًا لأن صلاحية وقت الترجمة للاستيراد في
index.d.ts
تعتمد على إعدادات التحويل البرمجي المحددة، والتي لا يرثها المستخدمون من أنواعك، فإن استخدام هذا النمط في DefinitelyTyped سيجبر المستخدمين على تغيير إعدادات التحويل البرمجي الخاصة بهم، والتي قد تكون غير صحيحة لوقت التشغيل الخاص بهم. بدلاً من ذلك، يجب عليك كتابة استيراد CJS لتصدير CJS لضمان توافق واسع النطاق ومستقل عن التكوين:// index.d.ts // CJS import, modeling `const Component = require("./component")` in JS import Component = require ( "./component" ) ;
package.json
هذا الملف مطلوب ويجب أن يتبع هذا القالب:
{
"private" : true ,
"name" : "@types/PACKAGE-NAME" ,
"version" : "1.2.9999" ,
"projects" : [
"https://aframe.io/"
] ,
"dependencies" : {
"@types/DEPENDENCY-1" : "*" ,
"@types/DEPENDENCY-2" : "*"
} ,
"devDependencies" : {
"@types/PACKAGE-NAME" : "workspace:."
} ,
"owners" : [
{
"name" : "Your Name Here" ,
"githubUsername" : "ghost"
}
]
}
تحدد package.json
جميع التبعيات، بما في ذلك حزم @types
الأخرى.
يجب عليك إضافة تبعيات غير @types
إلى قائمة التبعيات الخارجية المسموح بها. بيكادي هو مثال جيد. تمت الموافقة على هذه الإضافات من قبل المشرف، مما يمنحنا الفرصة للتأكد من أن حزم @types
لا تعتمد على حزم ضارة.
إذا كانت حزمة التنفيذ تستخدم ESM وتحدد "type": "module"
، فيجب عليك تعديل package.json ليطابق:
{
"type" : " module "
}
وينطبق هذا أيضًا إذا كانت حزمة التنفيذ تحتوي على exports
في package.json الخاص بها.
تسمح الكتابة بالتأكيد peerDependencies
في package.json
. يمكن أن تساعد تبعيات النظير في منع المواقف التي يقوم فيها مدير الحزم بتثبيت إصدارات جديدة جدًا أو أكثر من إصدار واحد من نفس الحزمة بشكل غير متوقع. ومع ذلك، فإن تبعيات الأقران لها جوانب سلبية؛ يختلف مديرو الحزم في تعاملهم مع تبعيات الأقران (على سبيل المثال، لا يقوم yarn
بتثبيتها تلقائيًا، ويتطلب npm
--legacy-peer-deps
لعدم التطابق). على هذا النحو، فإن المستفيدين الرئيسيين الذين يقدمون تبعيات نظير جديدة يتطلبون موافقة المشرف ويجب أن يقتصر ذلك على ظروف محددة.
بشكل عام، يجب أن تحتوي حزم الأنواع على تبعية نظير فقط إذا كانت الحزمة الأولية تحتوي على تبعية نظير على نفس الحزمة (أو أنواعها). على سبيل المثال، يمكن لحزمة DT لمكون React تحديد تبعية نظير على @types/react@*
، حيث سيحتاج المستهلك إلى تثبيت @types/react
لاستخدام JSX في المقام الأول. إذا قام المستهلك بتثبيت @types/react@16
في مشروعه، ولكن يتوفر إصدار أحدث من @types/react
على npm، فقد تساعد تبعية النظير مدير الحزم في اختيار @types/react@16
بدلاً من هذا الإصدار الأحدث. وبالمثل، chai-as-promised
لديه اعتماد نظير على chai
، لذلك يجب أن يكون لدى @types/chai-as-promised
اعتماد نظير على @types/chai
.
هناك بعض الحالات التي لا تحتوي فيها الحزمة الأولية على تبعية نظير على حزمة الأنواع، لكن تبعية النظير لا تزال مناسبة. هذه هي الحالات النموذجية التي تقوم فيها الحزمة الأولية بتوسيع حزمة أخرى وتفترض أنها موجودة، لذا كان يجب الإعلان عن تبعية نظير أثناء توسيع حزمة أخرى، لكنها لم تفعل ذلك. على سبيل المثال، يقوم chai-match-pattern
بتوسيع chai
، ولكنه لا يعلن عن اعتماد نظير على chai
، ولكنه يحتاج إليه ليعمل. يجب أن يكون لدى @types/chai-match-pattern
تبعية نظير على @types/chai
.
إذا كشفت الحزمة ببساطة عن أنواع من حزمة أخرى كجزء من واجهة برمجة التطبيقات (API) الخاصة بها بسبب التبعية العادية في الحزمة الأولية، فيجب ألا تستخدم تبعية نظير. على سبيل المثال، يحتوي express
على qs
في "dependencies"
. عندما يقوم المستخدمون بتثبيت express
، فلن يحتاجوا إلى تثبيت qs
يدويًا. وبالمثل، @types/express
يحتوي على @types/qs
في "dependencies"
. سيكون من غير الصحيح الإعلان عن @types/qs
باعتباره تبعية نظير لـ @types/express
، نظرًا لأن ذلك سيتطلب من بعض مستهلكي المصب تثبيت @types/qs
يدويًا.
.npmignore
يحدد هذا الملف الملفات التي سيتم تضمينها في كل حزمة @types
. ويجب أن تتخذ شكلاً محددًا. بالنسبة للحزم التي تحتوي على إصدار واحد فقط في الريبو:
*
! ** / * .d.ts
! ** / * .d.cts
! ** / * .d.mts
! ** / * .d. * .ts
وهذا يعني "تجاهل كافة الملفات، لكن لا تتجاهل أي ملفات تعريف". بالنسبة للحزم التي تحتوي على أكثر من إصدار واحد في الريبو، يجب أن يحتوي الإصدار "الأحدث" (في المستوى الأعلى) على شيء مثل:
*
! ** / * .d.ts
! ** / * .d.cts
! ** / * .d.mts
! ** / * .d. * .ts
/ v15 /
/ v16 /
/ v17 /
وهو نفس ملف .npmignore
السابق ولكنه يتجاهل كل دليل من الدلائل الفرعية التي تم إصدارها.
سوف يفشل CI إذا كان هذا الملف يحتوي على محتويات خاطئة ويوفر القيمة المقصودة. وبغض النظر عما يحتويه هذا الملف، فسيقوم الناشر بنشر ملفات الإقرار فقط.
pnpm dprint fmt -- 'path/to/package/**/*.ts'
..vscode/settings.template.json
(أو ما يعادله للمحررين الآخرين) للتنسيق عند الحفظ باستخدام ملحق VS Code dprintfunction sum(nums: number[]): number
: استخدم ReadonlyArray
إذا لم تكتب الدالة إلى معلماتها.interface Foo { new(): Foo; }
: يحدد هذا نوع الكائنات القابلة للإنشاء حديثًا. ربما تريد declare class Foo { constructor(); }
.const Class: { new(): IClass; }
: تفضل استخدام إعلان الفصل class Class { constructor(); }
بدلاً من الثابت الجديد.getMeAT<T>(): T
: إذا لم تظهر معلمة النوع في أنواع أي معلمات، فلن يكون لديك حقًا وظيفة عامة، بل لديك فقط تأكيد نوع مقنع. تفضل استخدام تأكيد النوع الحقيقي، على سبيل المثال getMeAT() as number
. مثال حيث تكون معلمة النوع مقبولة: function id<T>(value: T): T;
. مثال حيث يكون غير مقبول: function parseJson<T>(json: string): T;
. الاستثناء: new Map<string, number>()
على ما يرام.Function
و Object
فكرة جيدة على الإطلاق. في 99% من الحالات، من الممكن تحديد نوع أكثر تحديدًا. الأمثلة هي (x: number) => number
للوظائف و { x: number, y: number }
للكائنات. إذا لم يكن هناك يقين على الإطلاق بشأن النوع، any
هو الاختيار الصحيح، وليس Object
. إذا كانت الحقيقة الوحيدة المعروفة عن النوع هي أنه كائن ما، فاستخدم object
الكتابة وليس Object
أو { [key: string]: any }
.var foo: string | any
: عند استخدام any
في نوع اتحاد، يظل النوع الناتج هو any
. لذلك، على الرغم من أن جزء string
من هذا النوع من التعليقات التوضيحية قد يبدو مفيدًا، إلا أنه في الواقع لا يقدم أي فحص إضافي للكتابة بدلاً من مجرد استخدام any
. اعتمادًا على النية، يمكن أن تكون البدائل المقبولة any
string
أو string | object
.TL;DR: لا تقم بتعديل
.github/CODEOWNERS
، قم دائمًا بتعديل قائمة المالكين فيpackage.json
.
لدى DT مفهوم "أصحاب التعريفات" وهم الأشخاص الذين يرغبون في الحفاظ على جودة أنواع معينة من الوحدات.
لإضافة نفسك كمالك تعريف، قم بتعديل مصفوفة owners
في package.json
:
"owners" : [
{
"name" : " Some Person " ,
"githubUsername" : " somebody "
},
{
"name" : " Some Corp " ,
"url" : " https://example.org "
}
]
لاحظ أن هذه القائمة لا تستخدم لتوفير الاعتماد للمساهمات؛ يتم استخدامه فقط لإدارة مراجعات العلاقات العامة.
تتم مزامنة مالكي التعريفات مرة واحدة في الأسبوع مع الملف .github/CODEOWNERS وهو مصدر الحقيقة لدينا.
يعد Definitely Typed واحدًا من أكثر المستودعات نشاطًا على GitHub. ربما تساءلت كيف جاء المشروع. كتب @johnnyreilly تاريخًا مكتوبًا بالتأكيد. إنه يحكي قصة الأيام الأولى لـ Definitely Typed، بدءًا من المستودع الذي أنشأه @borisyankov، إلى النقطة التي أصبح فيها جزءًا محوريًا من نظام TypeScript البيئي. يمكنك قراءة قصة بالتأكيد كتبت هنا.
@types
على npm؟ يتم نشر الفرع master
تلقائيًا إلى نطاق @types
على npm بفضل أدوات DefinitelyTyped.
يعتمد الأمر على ذلك، ولكن سيتم دمج معظم طلبات السحب خلال أسبوع. يمكن دمج بعض العلاقات العامة بواسطة مالكي الوحدة ويمكن دمجها بشكل أسرع. تقريبا:
سيتم دمج العلاقات العامة التي تغير فقط أنواع الوحدة ولها تغييرات الاختبارات المقابلة بشكل أسرع بكثير
عادة ما يتم دمج العلاقات العامة التي تمت الموافقة عليها من قبل المالك المدرج في package.json
الخاص بالتعريف بسرعة أكبر؛ ستستغرق طلبات الحصول على التعريفات الخاصة بالتعريفات الجديدة وقتًا أطول لأنها تتطلب مزيدًا من المراجعة من المشرفين. تتم مراجعة كل علاقات عامة بواسطة أحد أعضاء فريق TypeScript أو Definitely Typed قبل دمجها، لذا يرجى التحلي بالصبر لأن العوامل البشرية قد تسبب تأخيرات. تحقق من لوحة حالة طلب السحب الجديدة لمعرفة التقدم أثناء عمل المشرفين من خلال العلاقات العامة المفتوحة.
بالنسبة للتغييرات التي يتم إجراؤها على الوحدات الشائعة جدًا، على سبيل المثال Node/Express/Jest والتي تحتوي على ملايين التنزيلات كل أسبوع على npm، تكون متطلبات المساهمات أعلى قليلاً. يمكن أن يكون للتغييرات في هذه المشاريع آثار هائلة على النظام البيئي، ولذا فإننا نتعامل مع التغييرات التي تطرأ عليها بقدر كبير من الاهتمام. تتطلب هذه الوحدات تسجيل خروج من مشرف DT ودعمًا متحمسًا من مالكي الوحدات. يمكن أن يكون مستوى اجتياز هذا مرتفعًا جدًا وغالبًا ما يصبح العلاقات العامة قديمة لأنه لا يوجد بطل. إذا وجدت أن لا أحد يلتزم، فحاول أن تجعل علاقاتك العامة تركز بشكل أقل.
@types
npm؟يجب تحديث حزم npm خلال ساعة. إذا مر أكثر من ساعة، فاذكر رقم العلاقات العامة على القناة المكتوبة بالتأكيد على خادم TypeScript Community Discord وسيحصل المشرف الحالي على عضو الفريق الصحيح للتحقيق.
<reference types="" />
أو الاستيراد؟ إذا كانت الوحدة التي تشير إليها هي وحدة (تستخدم export
)، فاستخدم عملية الاستيراد. إذا كانت الوحدة التي تشير إليها هي وحدة محيطة (تستخدم declare module
) أو تعلن فقط عن الوحدات العامة، فاستخدم <reference types="" />
.
tsconfig.json
يفتقد "noImplicitAny": true
أو "noImplicitThis": true
أو "strictNullChecks": true
.إذن فهم مخطئون ولم نلاحظ ذلك بعد. يمكنك المساعدة من خلال تقديم طلب سحب لإصلاحها.
نعم باستخدام dprint. نوصي باستخدام ملحق dprint لمحررك.
وبدلاً من ذلك، يمكنك تمكين خطاف git الذي سيقوم بتنسيق التعليمات البرمجية الخاصة بك تلقائيًا. قم بتشغيل pnpm run setup-hooks
. بعد ذلك، عند الالتزام، سيتم تنفيذ أمر dprint fmt
على الملفات التي تم تغييرها. إذا استفدت من الاستنساخ الجزئي، فتأكد من استدعاء git sparse-checkout add .husky
للتحقق من git Hooks قبل تشغيل البرنامج النصي setup-hooks
.
لا تتطلب طلبات السحب التنسيق الصحيح ليتم دمجها. ستتم إعادة تنسيق أي رمز غير منسق تلقائيًا بعد دمجه.
إذا كنت من مستخدمي VS Code، فنقترح عليك نسخ ملف
.vscode/settings.template.json
إلى.vscode/settings.json
. يقوم هذا القالب بتعيين ملحق dprint VS Code باعتباره المنسق الافتراضي في الريبو.
فيما يلي التعريفات المطلوبة حاليًا.
إذا كانت الأنواع جزءًا من معيار الويب، فيجب إضافتها إلى TypeScript-DOM-lib-generator حتى تصبح جزءًا من lib.dom.d.ts
الافتراضي.
إذا لم يكن هناك كود JavaScript مصدر على الإطلاق، على سبيل المثال، إذا كنت تكتب أنواعًا مساعدة أو أنواعًا لمواصفات معينة، فيجب عليك نشر الأنواع بنفسك، وليس على Definitely Typed. نظرًا لأنها تهدف إلى توفير أنواع لتعليمات JavaScript البرمجية الموجودة، فليس من المفترض أن يتم استيراد حزم @types
مباشرةً. وهذا يعني أنه لا ينبغي عليك إنشاء حزمة مكتوبة بالتأكيد والمخصصة للاستخدام مثل import type { ... } from "@types/foo"
. ولا ينبغي أن تتوقع كتابة import type { ... } from "foo"
في حالة عدم تثبيت foo
.
ويختلف هذا عن توفير أنواع للمتصفح فقط لمكتبة JavaScript أو أنواع لبيئة بأكملها مثل العقدة والكعكة وما إلى ذلك. هناك، يتم حل الأنواع إما ضمنيًا أو باستخدام /// <references types="foo" />
.
تقوم بعض الحزم، مثل chai-http، بتصدير دالة.
استيراد هذه الوحدة النمطية بنمط ES6 في النموذج import * as foo from "foo";
يؤدي إلى الخطأ:
خطأ TS2497: تم حل الوحدة النمطية 'foo' إلى كيان غير وحدة نمطية ولا يمكن استيرادها باستخدام هذه البنية.
يمكن منع هذا الخطأ عن طريق دمج تعريف الدالة مع مساحة اسم فارغة بنفس الاسم، ولكن لا ينصح بهذه الممارسة. هذه إجابة Stack Overflow يتم الاستشهاد بها بشكل شائع بخصوص هذه المسألة.
من الأفضل استيراد الوحدة باستخدام import foo = require("foo");
بناء الجملة. ومع ذلك، إذا كنت تريد استخدام استيراد افتراضي مثل import foo from "foo";
لديك خياران:
--allowSyntheticDefaultImports
إذا كان وقت تشغيل الوحدة لديك يدعم نظام التشغيل المتداخل للوحدات غير التابعة لـ ECMAScript، أي إذا كانت عمليات الاستيراد الافتراضية تعمل في بيئتك (مثل Webpack وSystemJS وesm).--esModuleInterop
إذا كنت تريد أن تعتني TypeScript بالتشغيل المتداخل غير ECMAScript (منذ TypeScript 2.7). export =
، لكنني أفضل استخدام عمليات الاستيراد الافتراضية. هل يمكنني تغيير export =
export default
؟ كما هو الحال في السؤال السابق، ارجع إلى استخدام خيارات برنامج التحويل البرمجي --allowSyntheticDefaultImports
أو --esModuleInterop
.
لا تغير تعريف النوع إذا كان دقيقًا. بالنسبة لحزمة npm، يكون export =
دقيقًا إذا كانت node -p 'require("foo")'
تعمل على استيراد وحدة ويكون export default
دقيقًا إذا كانت node -p 'require("foo").default'
تعمل على استيراد وحدة. .
بعد ذلك، ستكون قد قمت بتعيين الحد الأدنى من الإصدار المدعوم عن طريق تحديد "minimumTypeScriptVersion": "XY"
في package.json
.
ومع ذلك، إذا كان مشروعك يحتاج إلى الحفاظ على الأنواع المتوافقة مع الإصدار 3.7 وما فوق، على سبيل المثال، في نفس الوقت مع الأنواع المتوافقة مع الإصدار 3.6 أو أقل، فستحتاج إلى استخدام ميزة typesVersions
. يمكنك العثور على شرح تفصيلي لهذه الميزة في وثائق TypeScript الرسمية.
إليك مثال قصير للبدء:
سيكون عليك إضافة typesVersions
إلى package.json
:
{
"private" : true ,
"types" : " index " ,
"typesVersions" : {
"<=3.6" : { "*" : [ " ts3.6/* " ] }
}
}
قم بإنشاء الدليل الفرعي المذكور في حقل typesVersions
داخل دليل الأنواع الخاص بك ( ts3.6/
في هذا المثال). سيدعم ts3.6/
إصدارات TypeScript 3.6 وما دونها، لذا انسخ الأنواع والاختبارات الموجودة هناك.
بالعودة إلى جذر الحزمة، قم بإضافة ميزات TypeScript 3.7 التي تريد استخدامها. عندما يقوم الأشخاص بتثبيت الحزمة، سيبدأ TypeScript 3.6 والإصدارات الأقدم من ts3.6/index.d.ts
، بينما سيبدأ TypeScript 3.7 والإصدارات الأحدث من index.d.ts
.
يمكنك إلقاء نظرة على بلوبيرد للحصول على مثال.
قد ينتمي هذا إلى TypeScript-DOM-lib-generator. انظر المبادئ التوجيهية هناك. إذا كان المعيار لا يزال مسودة، فهو ينتمي هنا. استخدم اسمًا يبدأ بـ dom-
وقم بتضمين رابط للمعيار كرابط "Project" في package.json
. عندما يتخرج من وضع المسودة، قد نقوم بإزالته من Definitely Typed وإهمال حزمة @types
المرتبطة.
ملاحظة: تفترض المناقشة في هذا القسم الإلمام بالإصدارات الدلالية
يتم إصدار كل حزمة مكتوبة بالتأكيد عند نشرها على npm. ستقوم أدوات DefinitelyTyped (الأداة التي تنشر حزم @types
إلى npm) بتعيين إصدار حزمة التصريح باستخدام رقم الإصدار major.minor.9999
المدرج في package.json
. على سبيل المثال، فيما يلي الأسطر القليلة الأولى من إعلانات نوع Node للإصدار 20.8.x
في وقت كتابة هذا التقرير:
{
"private" : true ,
"name" : " @types/node " ,
"version" : " 20.8.9999 "
}
نظرًا لأن الإصدار مُدرج على أنه 20.8.9999
، فإن إصدار npm من الحزمة @types/node
سيكون أيضًا 20.8.x
لاحظ أن الإصدار الموجود في package.json
يجب أن يحتوي فقط على الإصدار major.minor
(على سبيل المثال 10.12
) متبوعًا بـ .9999
. وذلك لأن أرقام الإصدار الرئيسية والثانوية فقط تتم محاذاتها بين حزم المكتبات وحزم تعريف النوع. (يهدف .9999
إلى التأكد من أن حزم @types
المحلية تكون دائمًا الأحدث أثناء التطوير المحلي.) تتم تهيئة رقم إصدار التصحيح لحزمة تعريف النوع (على سبيل المثال .0
في 20.8.0
) إلى الصفر بواسطة Definitely Typed ويتم زيادته في كل مرة يتم نشر حزمة @types/node
جديدة على npm لنفس الإصدار الرئيسي/الثانوي من المكتبة المقابلة.
في بعض الأحيان، يمكن أن تخرج إصدارات حزمة إعلان الكتابة وإصدارات حزمة المكتبة من المزامنة. فيما يلي بعض الأسباب الشائعة وراء ذلك، مرتبة حسب مدى إزعاج مستخدمي المكتبة. عادةً ما تكون الحالة الأخيرة فقط مشكلة.
@types
الخاصة بها، فيجب أن يعمل npm update
عادةً. ❗ إذا كنت تقوم بتحديث إعلانات النوع لمكتبة، فقم دائمًا بتعيين الإصدار major.minor
في package.json
لمطابقة إصدار المكتبة التي تقوم بتوثيقها! ❗
يتطلب الإصدار الدلالي أن الإصدارات ذات التغييرات العاجلة يجب أن تزيد رقم الإصدار الرئيسي. على سبيل المثال، المكتبة التي تزيل دالة تم تصديرها بشكل عام بعد إصدارها 3.5.8
، يجب أن ترفع نسختها إلى 4.0.0
في إصدارها التالي. علاوة على ذلك، عند انتهاء إصدار المكتبة 4.0.0
، يجب أيضًا تحديث حزمة تعريف النوع Definitely Typed إلى 4.0.0
، بما في ذلك أي تغييرات جذرية في واجهة برمجة تطبيقات المكتبة.
تحتوي العديد من المكتبات على قاعدة كبيرة مثبتة من المطورين (بما في ذلك مشرفو الحزم الأخرى الذين يستخدمون تلك المكتبة كتبعية) والذين لن ينتقلوا على الفور إلى إصدار جديد يحتوي على تغييرات معطلة، لأنه قد يستغرق الأمر أشهرًا حتى يتوفر لدى المشرف الوقت لإعادة الكتابة كود للتكيف مع الإصدار الجديد. في هذه الأثناء، قد لا يزال مستخدمو إصدارات المكتبة القديمة يرغبون في تحديث إعلانات النوع للإصدارات الأقدم.
إذا كنت تنوي الاستمرار في تحديث الإصدار الأقدم من إعلانات النوع الخاصة بالمكتبة، فيمكنك إنشاء مجلد فرعي جديد (على سبيل المثال /v2/
) مسمى للإصدار الحالي (الذي سيصبح "قديمًا" قريبًا) ونسخ الملفات الموجودة من الإصدار الحالي إليه .
عند إنشاء مجلد إصدار جديد، تأكد من تحديث حقل إصدار package.json
؛ سيتم حل pnpm
تلقائيًا لهذه الحزمة ذات الإصدار عند الحاجة إليها. إذا كانت الحزم الأخرى في الريبو تحتاج إلى الاعتماد على هذا الإصدار الجديد، فتأكد من تحديث package.json
الخاص بها أيضًا.
على سبيل المثال، إذا كنا نقوم بإنشاء types/history/v2
، فستبدو package.json
الخاصة بها كما يلي:
{
"private" : true ,
"name" : " @types/history " ,
"version" : " 2.4.9999 "
}
قد تقوم حزمة أخرى بتحديد هذا الإصدار عن طريق تحديد:
{
"private" : true ,
"name" : " @types/browser-sync " ,
"version" : " 2.26.9999 " ,
"dependencies" : {
"@types/history" : " ^2 "
}
}
أيضًا، /// <reference types=".." />
لن يعمل مع تعيين المسار، لذلك يجب أن تستخدم التبعيات import
.
تقوم حزم @types
دائمًا بكتابة حزم من نفس الإصدار، لذا فإن @types/[email protected]
مخصصة لـ [email protected]
. ونتيجة لذلك، يتم نشر جميع التغييرات، سواء كانت معطلة أم لا، كمراجعات تصحيحية، ما لم تقترن بتعديل كبير/ثانوي لتغيير إصدار الحزمة المستهدفة (سواء كان ذلك بالصدفة أم لا).
عندما يتعلق الأمر بكسر التغييرات، يأخذ مشرفو DT في الاعتبار مدى شعبية الحزمة، وإيجابيات تغيير الكسر المقترح، والجهد الذي سيتطلبه المستخدمون لإصلاح التعليمات البرمجية الخاصة بهم، وما إذا كان من الممكن تأخير التغيير بشكل معقول حتى يمكن مزامنته مع نتوء كبير للمكتبة المنبع.
يحتوي دليل TypeScript على معلومات عامة ممتازة حول كتابة التعريفات وأيضًا ملف التعريف النموذجي هذا الذي يوضح كيفية إنشاء تعريف باستخدام بناء جملة الوحدة النمطية ES6، مع تحديد الكائنات المتاحة للنطاق العام أيضًا. تم توضيح هذه التقنية عمليًا في تعريف big.js
، وهي مكتبة يمكن تحميلها عالميًا عبر علامة البرنامج النصي على صفحة ويب أو استيرادها عبر عمليات الاستيراد المطلوبة أو نمط ES6.
لاختبار كيفية استخدام تعريفك عند الإشارة إليه عالميًا أو كوحدة نمطية مستوردة، قم بإنشاء مجلد test
ووضع ملفي اختبار هناك. قم بتسمية YourLibraryName-global.test.ts
والآخر YourLibraryName-module.test.ts
. يجب أن يمارس ملف الاختبار العام التعريف وفقًا لكيفية استخدامه في البرنامج النصي الذي تم تحميله على صفحة ويب حيث تكون المكتبة متاحة على النطاق العالمي - في هذا السيناريو، يجب ألا تحدد عبارة استيراد. يجب أن يستخدم ملف اختبار الوحدة التعريف وفقًا لكيفية استخدامه عند استيراده (بما في ذلك بيان (بيانات) import
). إذا قمت بتحديد خاصية files
في ملف tsconfig.json
الخاص بك ، فتأكد من تضمين كل من ملفات الاختبار. مثال عملي على ذلك متاح أيضًا على تعريف big.js
يرجى ملاحظة أنه ليس من الضروري ممارسة التعريف بشكل كامل في كل ملف اختبار - يكفي اختبار العناصر التي يمكن الوصول إليها عالميًا فقط في ملف الاختبار العالمي وممارسة التعريف بالكامل في ملف اختبار الوحدة النمطية أو العكس.
يجب أن تذهب أنواع الحزمة الناطقة @foo/bar
في types/foo__bar
. لاحظ السطح المزدوج.
هذا المشروع مرخص بموجب ترخيص MIT.
حقوق الطبع والنشر على ملفات التعريف هي ذاتية لكل مساهم مدرج في بداية كل ملف تعريف.