الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

أساسيات لغة TypeScript

بدأه Mr.B في 5 أكتوبر 2012 · 3 رد · 2,354 مشاهدة · في قسم البرمجة بــ Javascript
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله وبركاته

# دليل المقالة :

- مدخل

- طريقة عمل اللغة

- ثُبوت النوع

- المتغيرات الإختيارية والقيم الإفتراضية

- الواجهات

- الفئات

- الوظائف والأعضاء

- الوراثة

- إعادة كتابة الوظائف

- الوحدات

# مدخل

كشفت مايكروسوفت قبل أربع أيام عن لغة جديدة مفتوحة المصدر برخصة أباتشي Apache إسمها تايب سكربت (تَايّبْ-سّكْرِبتْ) TypeScript كإمتداد للغة جافا سكربت JavaScript.

أضافت اللغة العديد من المزايا والتحسينات على جافا سكربت. فمع تطور الوُب أصبح هناك الكثير من التطبيقات التي تعمل من مُتصفح الوُب وتعمد على جافا سكربت إلا أن جافا سكربت ليست مناسبة ومتعبة في مشاريع الوُب الكبيرة.

عني أعجبتني اللغة كثيراً وأتوقع لها مُستقبل جيد. فإما أن تصبح جزء من جافا سكربت أو ستستبدلها لأنها وليدة حاجة وفعلاً أتت لتحل مُشكلة.

إن شاء الله ستكون هذه المقالة أول مقالة تشرحها. فاللغة لم تكمل الإسبوع, فقد يكون هناك تطوير ومزيد من الإضافات مستقبلاً.

# طريقة عمل اللغة

اللغة متكاملة 100% مع جافا سكربت وتعمل على أي مُتصفح يدعم جافا سكربت. فالبرنامج الذي ستكتبه بإستخدامها سيتحول عن طريق مُصرف compiler خاص بها لأقرب وأفضل برنامج جافا سكربت. فمثلاً لو كتبت :

class MyClass {
    public my_method() {
        document.writeln("Hello world!");
    }
}

var foo = new MyClass();
foo.my_method();

سيتحول لـ:

var MyClass = (function () {
    function MyClass() { }
    MyClass.prototype.my_method = function () {
        document.writeln("Hello world!");
    };
    return MyClass;
})();
var foo = new MyClass();
foo.my_method();

# ماذا تحتاج قبل البدء

تايب سكربت ليست سوى إمتداد لجافا سكربت. لذا يلزمك معرفة بأساسيات جافا سكربت. فلن أغطيها في هذه القالة لوجود العديد من المقالات والكتب لكتاب عرب بذلوا جهوداً رائعة في شرحها.

للغُة كما ذكرت مُصرف خاص بها يُحول أكوادها لجافا سكربت. يُمكنك الحصول عليه من هذه الصفحة أو يُمكنك تجربته دون تثبيت من هذه الصفحة TypeScript Playground.

لنبدأ بشرحها :

# ثُبوت النوع

في جافا سكربت, لو أعطيتك هذه الدالة :

function foo(a) {
    a *= 2;
    document.writeln(a);
}

لأن جافاسكرت لغة متغيرة النوع dynamic typing, لاتستطيع الجزم بنوع المتغير الذي تأخذة الدالة إلا بفهم عمل الدالة أو أنني أخبرك بنوعه.

لذا أضافت اللغة لجافا سكربت خاصية "ثُبوت النوع" static typing. ويُمكنك الآن تحديد نوع هذا المُتغير بإضافة نقطتين رأسيتين ":" بعد إسم المتغير متبوعة بنوعه إما رقم number أو نصّ string أو قيمة منطقية bool :

function foo(a:number) {
    a *= 2;
    document.writeln(a.toString());
}

أمثلة على الأنواع التي تدعمها :

var age:number  = 21;         /* متغير رقمي */
var name:string = "Barakat";  /* متغير نصي */
var male:bool   = true;       /* متغير منطقي */

وُيمكنك أن تجعل النوع متغير وعام بإستخدام any :

var foo:any;

foo = 21;
foo = "Hey";
foo = true;

بالنسبة للمصفوفات, يُمكنك إنشاء مصفوفة أرقام هكذا :

var array:number[] = [1, 2, 3];

document.writeln(array[0].toString() + "</br>");
document.writeln(array[1].toString() + "</br>");
document.writeln(array[2].toString() + "</br>");

هذا الشيء ينطبق على الوظائف والدوال, فُيمكنك تحديد نوع مُدخلات الدالة والوظيفة ومخرجاتها. مثلاً لنكتب دالة تخبرنا بأن العدد سالب أم لا حيث تأخذ رقم وتعيد قيمة منطقية صواب true أو خطأ false :

function isNegativ(num:number): bool {
    if( num < 0 )
        return true;
    return false;
}

الآن لو كتبت :

var x:number = isNegativ("2");

فسيعطيك المُصرف خطأ لسببين : أنك مررت نص للدالة بينما تأخذ الدالة رقم. السبب الثاني أنك جعلت المتغير الذي سيتقبل مخرجات الدالة رقم بينما الدالة تعيد قيمة منطقية.

عند تمرير الدوال لدوال إخرى , مؤشرات الدوال, فيلزمك الآن تحديد نوع مدخلات هذه الدالة ومخرجاتها قبل أن تُمررها :

function callForMe(param:string, callback: (param:string) => string) : bool {
    var local:string = callback(param);
    document.writeln(local);
    return true;
}

function myCallback(param:string) : string {
    return param + "</br>";
}


callForMe("Hello", myCallback);
callForMe("World", myCallback);

لاحظ كيف وصفنا المدخل الثاني في هذه الدالة بأنه لابد أن يكون دالة تأخذ نص وتعيد نص.

# المتغيرات الإختيارية

أضافت تايب سكربت المتغيرات الإختيارية. فمثلاً لو كانت لدينا هذه الدالة :

function foo(a:string, b:string) {
    document.writeln(a + "<br>");
    if(b != undefined)
        document.writeln(b + "<br>");
}

وأردنا أن نجعل المتغير b إختياري, فُيمكن عمل ذلك بإضافة علامة إستفهام بعده b?:string :

function foo(a:string, b?:string) {
    document.writeln(a + "<br>");
    if(b != undefined)
        document.writeln(b + "a<br>");
}

foo("One");
foo("Two", "Three");

سيتحمل المُتغير الإختياري القيمة undefined إذا لم يتم إسناده.

يُمكنك أيضاً أن تُعطي قيمة إفتراضية لمتغير إذا لم يتم إستناده هكذا :

function foo(a:number = 0) {
    a *= 10;
    document.writeln(a.toString() + "</br>");
}

foo();
foo(5);

# الواجهات

تتيح لك الواجهات interfaces وضع مجموعة من المُتغيرات أو الكائنات أو مشؤشرات للدوال تحت مجموعة واحدة وهي تحسين للـjson في جافا سكربت. لنُنشيء وآجهة إسمها الأشخاص Person وتحتوي الإسم-نص و العمر-رقم وهل هو ذكر-قيمة منطقية :

interface Person {
    name:string;
    age:number;
    male:bool;
}

يُمكنك إنشاء عنُصر منه وقراءة محتوياته هكذا :

interface Person {
    name:string;
    age:number;
    male:bool;
}

var person:Person = {name:"Barakat", age:21, male:true};

document.writeln("Name: " + person.name + "</br>");
document.writeln("Age  :" + person.age + "</br>");
document.writeln("Male : "+ person.male + "</br>");

لو نظرت لكيف سيطبقها المُصرف ستجد أنه قاموس أو json عادي:

var person = {
    name: "Barakat",
    age: 21,
    male: true
};
document.writeln("Name: " + person.name + "</br>");
document.writeln("Age  :" + person.age + "</br>");
document.writeln("Male : " + person.male + "</br>");

مثال على إستخدام الواجهات في الدوال والوظائف :

interface Person {
    name:string;
    age:number;
    male:bool;
}

function dumpPerson(person:Person) {
    document.writeln("Name: " + person.name + "</br>");
    document.writeln("Age  :" + person.age + "</br>");
    document.writeln("Male : " + person.male + "</br>");
}

dumpPerson({name:"Barakat", age:21, male:true});

يُمكن أيضاً جعل عنصراً ما من الواجهة إختياري وذلك بإستخدام علامة الإستفهام :

interface Info {
    necessary:string;
    optional?:string;
}

var info:Info = {necessary:"One"};

تعريف مصفوفة أرقام إسمها arrayNum ومصفوفة نصوص arrayStr ومؤشر لدالة callback تأخذ نص وتعيد رقم كعناصر:

interface Complex {
    arrayNum: number[];
    arrayStr: string[];
    callback: (param:string) => number;
}

var complex:Complex = {
    arrayNum: [1, 2, 3],
    arrayStr: ["One", "Two", "Three"],
    callback: function (a:string) : number { return 10;},
};

ويُمكن إضافة أي نوع للواجهات.

# الفئات

أضافت تايب سكربت للغة جافا سكربت ميزة الفئات classes ودعمت الكثير من مفاهيم البرمجة الكائنية بطريقة أنيقة تشبه طريقة جافا Java. فُيمكنك الآن إنشاء فئة فارغة فقط بكتابة :

class MyClass {

}

ولإنشاء كائن منها يُمكنك كتابة :

var myobject = new MyClass();

أو :

var myobject:MyClass = new MyClass();

# الوظائف والأعضاء

هناك عدد من الوظائف في تايب سكربت :

* وظيفة البنّاء وهي وظيفة خاصة إسمها constructor وأول وظيفة تُستدعى بعد إنشاء الفئة :

class MyClass {
    constructor(name:string) {
        document.writeln(name);
    }
}

var myobject = new MyClass("foo");

* الوظائف والأعضاء العامة والخاصة, ويلزم إنشاء كائن من الفئة للتعامل معها.

- الوظائف العامة: وظائف يُمكن إستدعاءها من خارج الفئة.

- الوظائف الخاصة: وظائف لايُمكن إستدعاءها من خارج الفئة, فقط بداخلها.

- العضو العام: متغير موجود داخل الفئة يُمكن قراءتها من خارجها.

- العضو الخاص: متغير موجود داخل الفئة لايُمكن قراءتها من خارجها.

class MyClass {
    public publicMember:string; /* عضو عام يُمكن قراءته وتعديله من داخل وخارج الفئة */
    private privateMember:string; /* عضو خاص يُمكن قراءته وتعديله فقط من خارج الفئة */

    constructor() {
        this.publicMember = "Public member";
        this.privateMember = "Private member";
    }

    public publicMethod() { /* وظيفة عامة يُمكن إستدعاءها من داخل خارج الفئة */
        this.privateMethod();
    }

    private privateMethod() {  /* وظيفة خاصة يُمكن إستدعاءها فقط من داخل الفئة */
        document.writeln(this.privateMember);
    }
}

var myobject = new MyClass();

myobject.publicMethod(); /* صحيح, إستدعاء فئة عامة */
document.writeln(myobject.publicMember); /* صحيح, قراءة عضو عام */

myobject.privateMethod(); /* خطأ إستدعاء وظيفة خاصة */
document.writeln(myobject.privateMember); /* خطأ قراءة عضو خاص */

* الوظائف الفئات الثابتة, وهي وظائف يُمكن إستدعاءها من خارج الفئة دون الحاجة لإنشاء كائن منها.

class Foo {
    static staticMember:string = "Static member </br>";

    static staticMethod() {
        document.writeln("Static method </br>");
    }
}

Foo.staticMethod();
document.writeln(Foo.member);

لاحظ أنه لايُوجد أي إنشاء لأي كائن من الفئة Foo ورغم ذلك أمكننا إستدعاء staticMethod الفئة وقراءة قيمة .

يُمكنك أيضاً أن تكتب بدلاً من :

class MyClass {
    private member:string;

    constructor(member:string) {
        this.member = member;
    }

    public getMember(): string {
        return this.member;
    }
}
var myobject = new MyClass("foo");
var foo:string = myobject.getMember();
document.writeln(foo);

يُمكنك إختصارها هكذا :

class MyClass {
    constructor(private member:string) {

    }

    public getMember(): string {
        return this.member;
    }
}

var myobject = new MyClass("foo");
var foo:string = myobject.getMember();
document.writeln(foo);

والنتيجة واحدة.

# الوراثة

سهلت كثيراً تايب سكربت الوراثة, فُيمكنك الآن وراثة فئة فقط بإستخدام الكلمة extends , مثل جافا :

class BaseClass {
    private member:string = "I'm a member of BaseClass</br>";

    public iCameWithBase() {
        document.writeln("I came with base</br>");
    }

    public getMemeber() {
        document.writeln(this.member);
    }

}

class SubClass extends BaseClass {
    public iCameWithSub() {
        document.writeln("I came with sub</br>");
    }
}

var sub = new SubClass();
sub.iCameWithBase();
sub.iCameWithSub();
sub.getMemeber();

هنا فئة إسمها SubClass ترث جميع محتويات الفئة الأم iCameWithBase. فقط بهذه البساطة.

لو كانت لديك فئة إسمها Foo فيها بنّاء وترثها فئة إسمها Bar :

class Foo {
    constructor(private fooMember:string) {

    }

    public getFooMember() {
        document.writeln(this.fooMember + "</br>");
    }
}

class Bar extends Foo {

}


var bar = new Bar("foo");

bar.getFooMember();

لو أردت إضافة بناء للفئة الإبنة, فيُنمكنك عمل هذا بإضافة بناء طبيعي وإستدعاء بناء الفئة الأم بإستخدام super هكذا :

class Foo {
    constructor(private fooMember:string) {

    }

    public getFooMember() {
        document.writeln(this.fooMember + "</br>");
    }
}

class Bar extends Foo {
    constructor(private barMember:string, fooMember:string) {
        super(fooMember); /* إستدعينا بناء الفئة الأم ومررنا له قيمة */
    }

    public getBarMember() {
        document.writeln(this.barMember + "</br>");
    }
}


var bar = new Bar("bar", "foo");

bar.getFooMember();
bar.getBarMember();

# إعادة كتابة الوظائف

تعني إعادة كتابة الوظائف method override أن تُعيد كتابة وظيفة ورثتها الفئة من فئة أم :

class AppBase {
    public run() {
        document.writeln(this.doSomething());
    }

    private doSomething() : string {
        return "Nothing </br>";
    }
}

class MyApp extends AppBase {
    private doSomething() : string {
        return "Hello </br>";
    }
}
var app = new MyApp();

app.run();

كما رأيت, ففي المثال أعدنا كتابة الوظيفة doSomething في الفئة MyApp. هذه فعلياً نمط تصميم أكثر من كونه ميزة وتستخدمه الكثير من التطبيقات والمكتبات بنفس طريقة المثال.

# الوحدات

تعاني جافا سكربت من إفتقارها لوجود فضاء أسماء namespacing. فمثلاً لو كان لديك برنامج في جُزئين وتشابهت بهما دالة أو متغير بالإسم فستحدث مُشكلة لأن مُفسر جافا سكربت يرى كلا الدالتين في نفس الوقت.

حل هذه المُشكلة أضافت تايب سكربت الوُحدات modules والتي أضافت. يُمكنك إنشاء وحدة هكذا :

module MyModule1 {

}

module MyModule2 {

}

كل مابداخل الوحدتين MyModule1 وMyModule2 يُعتبر منفصل تماماً. لنُضف دالة ومتغير لكل واحدة:

module MyModule1 {
    var local:string = "MyModule1";

    function foo() {
        document.writeln("Hello form MyModule1!</br>");
    }
}

module MyModule2 {
    var local:string = "MyModule2";

    function foo() {
        document.writeln("Hello form MyModule2!</br>");
    }
}

الآن يُمكنك وضع كلُ وحدة في ملف منفصل ولن يحدث بينهما تعارض.

في ذلك المثال, foo وlocal تعتبران دالة ومتغير محلي ولايُمكن إستدعاءهما خارج تلك الوُحدة. لعمل هذا يلزمك إضافة الكلمة export قبل أي عنصر في الوحدة كي تستطيع إستخدامه من خارجها :

module MyModule1 {
    export var local:string = "MyModule1";

    export function foo() {
        document.writeln("Hello form MyModule1!</br>");
    }
}

module MyModule2 {
    export var local:string = "MyModule2";

    export function foo() {
        document.writeln("Hello form MyModule2!</br>");
    }
}

ولإستخدامها :

module MyModule1 {
    export var local:string = "MyModule1";

    export function foo() {
        document.writeln("Hello form MyModule1!</br>");
    }
}

module MyModule2 {
    export var local:string = "MyModule2";

    export function foo() {
        document.writeln("Hello form MyModule2!</br>");
    }
}

MyModule1.foo();
MyModule2.foo();

document.writeln(MyModule1.local + "</br>");
document.writeln(MyModule2.local + "</br>");

يُمكن عمل وحدات تتفرع من بعض هكذا :

module Root {
    export function foo() {
        document.writeln("Hello form Root!</br>");
    }
}

module Root.SubA {
    export function foo() {
        document.writeln("Hello form Root.SubA!</br>");
    }
}

module Root.SubB {
    export function foo() {
        document.writeln("Hello form Root.SubB!</br>");
    }
}

module Root.SubA.SubAA {
    export function foo() {
        document.writeln("Hello form Root.Sub1.SubAA!</br>");
    }
}

Root.foo()
Root.SubA.foo();
Root.SubB.foo();
Root.SubA.SubAA.foo();

لو مثلتها في شجرة فستبدو :

          Root
         __|__
        /     \
       /       \
     SubA     SubB
      |
    SubAA

في حال كان لديك ملف إسمه Util.ts , إمتداد ملفات اللغة ts, ويحتوي على الوحدة:

module Base {
    export function foo() {
        document.writeln("A.foo</br>");
    }
}

وتريد إستيراده من ملف آخر إسمه App.ts, فيُمكنك عمل هذا بالكتابة في الملف App.ts:

///<reference path='Util.ts' />

import Base = module("Base");

Base.foo();

في السطر الأوّل قُمنا بإدراج الملف Util.ts. وفي السطر الثاني حددنا إسم الوحدة التي نُريد إستخدامها بـBase.

تعتبر تايب سكربت كُل ملف على أنّه وحدة مستقلة. فمثلاً لو كان لديك الملف Base.ts ويحتوي :

export function foo() {
    document.writeln("foo");
}

فيمكن إستيراده من الملف App.ts هكذا :

import Base = module(".\Base");

Base.foo();

هذا ما إستطعت جمعه من معلومات حول اللغة, أتمنى أنك إستفدت من المقالة.

بالتوفيق.

تم تعديل هذه المشاركة بواسطة Mr.B في 5 أكتوبر 2012 في 03:54

5
#2

ماشاء الله

بجد شرح ممتع جدا وتوضيح رائع

تسلم ايدك وبارك الله فيك

جارى بداية التنفيذ

1

سبحان الله وبحمده , سبحان الله العظيم

مدونتى ( مدونة نظرة بعمق )

=======================

GSM | GPRS |CDMA |UMTS | LTE | RHCE

#3

السلام عليكم ورحمه الله وبركاته

شكرا اخي على هذا التوضيح, كنت سوف اكتب عن الموضوع نفسه في اليوم الذي تم اطلاق TypeScript لأني سمعت درس يوضح التقنية وامكانيتها وكان المتحدث Andres Hejlsberg الغني عن التعريف, مرة اخرى اشكرك اخي على الايضاح .. واتمنى لك المزيد من الابداع ..

1

.:: Wish to become better and better ::.

#4

أكرمك الله أخي ووفقك لكل خير

1

ما أقبـح المعصية ، تذهب لذتها ويبقى إثمها ... ومأ أحسن الطاعة ، تذهب مشقتها ويبقى ثوابها

كل نعيم دون الجنة غرور ... وكـل شقـاء دون النـار سرور

الدورة التطبيقية لتعليم التصميم بالإليستريتور

مواضيع مشابهة