Типы в машинописном тексте

Примитивные типы:

Типы int/string/float также предполагаются исходя из начального значения.

let s = 'alam'
s = 12 //shows error

Но если вы не хотите устанавливать значение, а просто объявляете переменную типа Java, C++ с типом, тогда

let character: string;
let age: number;
let isLoggedIn: boolean;
// age = 'luigi' //shows error
age = 30

Но вы также можете разрешить переменной принимать типы Union(mixed).

let uid: string|number;
uid = '123'
uid = 'one two three'
uid = true //shows error, add boolean to be an acceptable type

множество

  • Массив одного типа: после создания Typescript не позволит помещать/устанавливать различные типы элементов в массив строк, например java/c#. Типы автоматически принимаются компилятором.
let names = ['luigi', 'mario']
// in typescript when you create array with a type of elements that cannot be 
// changed localStorage(just like java/c#)
names.push('toad')
// names.push(3), shows error
// names[0] = 3, shows arror
  • Массив смешанного типа: но если вы действительно хотите, вы можете создать смешанный массив, указав, какие объекты вы разрешаете, с конкретными элементами. В этом случае компилятор машинописного текста предположит, что вы хотите, чтобы эти типы принимались.
// lets deffine a mixed type array, whatever type you want to be allowed,
//put them in the initial stage for the compiler to understand.
let mixed = ['ken', 4, 'ch',true]
mixed.push('ryu')
mixed.push(10)

Объявить массив определенного типа без присвоения значений:

let ninjas: string[];
ninjas = ['x']

простое объявление означает, что массив имеет значение Null, он еще не имеет никакого значения. если мы хотим отправить, нам нужно присвоить пустое значение массива.

let ninjas: string[] = []
ninjas.push('sds')

Объявление смешанного типа массива с типом UNION без значений:

let mixed:(string|number) [] = [];
mixed.push('hello')
mixed.push(20)
mixed.push(true)//shows error, to add boolean capability, add boolean in declaration

Объект:

  • после создания объекта вы не можете изменять значения с различными значениями типа в свойствах объекта.
let ninja = {
  name: 'mario',
  belt: 'black',
  age: 30
}

ninja.age = 40;
ninja.name = 'ryu';
//cant assign string to integer property age
// ninja.age = '30'
  • как только вы создадите объект, вы не сможете присвоить этой переменной целое число или строку. эта переменная фиксирована и ей присваивается только объект, не только объект, но только с точно такими же свойствами и одинаковым количеством свойств.
let ninja = {
  name: 'mario',
  belt: 'black',
  age: 30
}

ninja = {
  name: 'yoshi',
  belt: 'oragne',
  age:40
}

let ninja = {
  name: 'mario',
  belt: 'black',
  age: '30', //shows error
  skills: 'newskil'//shows error, cannot add a new property
}

Объявление объектной переменной определенного типа без значения:

let ninjaOne: object;
ninjaOne = {name: 'yoshi', age: 30}
ninjaOne = [] // also works as array is a kind of object

но мы также можем исправить точную подпись объекта, не принимая какой-либо объект.

let ninjaTwo: {
  name: string,
  age: number,
  beltColor: string
}
ninjaTwo = {} //not acceptable
ninjaTwo = { name: 'mario', age:20, beltColor: 'blue'} //acceptable
ninjaTwo = { name: 'mario', age:20, beltColor: 'blue', skill: 'c++'} //not acceptable

Разрешение любых типов (например, JS, Python) с помощью any:

let age: any = 25;
age = true;
console.log(age)
age = 15
console.log(age)
age = {
    name: 'luigi'
}
console.log(age)

создание массива любого типа, чтобы мы могли передать значение любого типа:

let mixed: any[] = []
mixed.push(5)
mixed.push(true)
console.log(mixed)

создавая объект любого типа, это приведет к тому, что переменная должна получить значение, соответствующее подписи, но подпись имеет любое поле.

let ninja:{ name: any, age: any}
ninja = {
    name:'yoshi',
    age:25
}

ninja = {
    name:'yoshi',
    age:true
}
console.log(ninja) //this will also work, so USE WITH CAUTION

Машинописные функции

когда вы объявляете функцию и присваиваете ее переменной, компилятор принимает тип этой переменной как функцию, и вы не можете позже изменить значение с помощью примитивного типа.

let greet = () =>{
    console.log('hello')
}

greet()
greet = 12 //shows error

но, как и в случае с int, числом, массивом и объектами, вы также можете просто объявить, что переменная будет содержать функцию, но не назначать функцию сразу.

let greetFunc: Function;

greetFunc = () =>{
    console.log('hello')
}

greetFunc()

Объявление переменных, которые принимают функции только с фиксированными сигнатурами.

let gree: (a:string, b:string) => void;
gree = (name:string, greeting:string) =>{
    console.log(`${name} says ${greeting}`)
}

// the variables name can be anything, does not have to be a and b. but
//the variable types, and return types shouldmatch
gree('xy','zw')

gree = (name:string, greeting:number) =>{ //shows error, the signature doesnt
//match
    console.log(`${name} says ${greeting}`)
}

При сопоставлении сигнатуры функции она должна соответствовать аргументу, выводить все. следующий метод покажет ошибку vscode, так как, если третий аргумент не плюс, он ничего не возвращает, что означает возврат void, который не является сигнатурой метода.

let calc: (a:number, b:number, c:string) => number;
calc = (numOne:number, numTwo:number, action:string) => {
    if (action == 'plus'){
        return numOne + numTwo
    }
}
//to fix that
calc = (numOne:number, numTwo:number, action:string) => {
    if (action == 'plus'){
        return numOne + numTwo
    }
else{
return 0
}

Указание типов параметров функции с использованием предыдущих обозначений фиксированных типов.

//the following function only expects two integers.
const add = (a:number, b: number) =>{
    console.log(a+b)
}
add(7,8)

//using the union to accept string also
const add = (a:number, b: number|string) =>{
    console.log(a+b)
}
add(7,8)
add(7,'eight')

Union также можно использовать для обеспечения соблюдения допустимых значений. Здесь мы принимаем последний аргумент только как начало или конец.

render(item: HasFormatter, heading: string, pos: 'start' | 'end'){
        
    }

По умолчанию все параметры являются обязательными. Вы можете добавить дополнительный параметр со знаком вопроса. Необязательное значение параметра не определено, если оно не передано.

const add = (a:number, b?: number) =>{
    console.log(a)
//when b is not passed it is NaN/undefined
}

add(7)

Необязательный параметр со значением по умолчанию, вопросительный знак нам больше не нужен. Простое предоставление значения по умолчанию делает параметр необязательным со значением по умолчанию.

const add = (a:number, b: number=15) =>{
    console.log(a+b)
}

add(7) //prints 22
add(7,7) //prints 14

Необязательные параметры всегда следует указывать в конце, иначе все запутается.

Если у вас есть функция, которая возвращает переменную типа (здесь число), то присвоение результата вызова функции переменной приводит к тому, что тип переменной равен числу.

const minus = (a:number, b: number)=>{
    return a*b;
}

let result = minus(10,7)
result = 'a' //shows error, from the previous line, 
// compiler assumed result is number only

объявление типа возвращаемого значения функции:

хотя, как и в приведенном выше примере, присвоение результата функции переменной позволяет компилятору автоматически определить тип, но для ясности типа возвращаемого значения функции большого метода вы должны использовать тип возвращаемого значения.

const minus = (a:number, b: number):number =>{
    return a*b;
}

let result = minus(10,7)
result = 5

когда вы ничего не возвращаете из метода, компилятор машинописного текста определяет тип возвращаемого значения как void. при наведении курсора на метод в коде vs. но вы все равно можете определить это, если необходимо.

const add = (a:number, b: number=15) =>{
    console.log(a+b)
} //it is void return type method

//but you can still define
const add = (a:number, b: number=15):void =>{
    console.log(a+b)
}

Упрощение объявлений типов с помощью псевдонимов типов:

const logDetails = (uid: string |number, item:string) =>{
    console.log(`${item} has a uid of ${uid}`);
}

logDetails(12,'a')

type stringOrnumber = string |number
const logDetails = (uid: stringOrnumber, item:string) =>{
    console.log(`${item} has a uid of ${uid}`);
}
logDetails(12,'a')

Мы также можем объявить тип объекта. повторное использование ранее определенных типов.

const greet = (user: { name:string, uid:string|number})=>{
    console.log(user.name)
}
type stringOrnumber = string |number
type ObjWithName = { name:string, uid: stringOrnumber}
const greet = (user: user: ObjWithName)=>{
    console.log(user.name)
}

Псевдонимы типов уменьшают дублирование кода.

переменным также можно заставить иметь определенную сигнатуру функции только с определенными параметрами сигнатуры объекта, используя псевдонимы типов.

let logDetails: (obj: {name: string, age: number}) => void;

logDetails =  (ninja: {name:string, age:number}) =>{
    console.log(`${ninja.name} is ${ninja.age} years old`)
}

type person = {name:string, age:number}
logDetails =  (ninja: person) =>{
    console.log(`${ninja.name} is ${ninja.age} years old`)
}

Взаимодействие с домом:

! метод для отметки ненулевого значения:

const anchor = document.querySelector("a");

console.log(anchor.href);//shows error as ts doesnt know if anchor is null
//means anchrotag could be absent.

//if you are sure there is an anchrotag a in the html exist
//then put a ! mark
const anchor = document.querySelector("a")!; //exclamation to mean anchrotag
//is not null

console.log(anchor.href);

когда вы объявляете и назначаете тег привязки. Typescript предполагает, что переменная привязки представляет собой HTML-тег привязки тип. Наведите указатель мыши на переменную привязки, и вы увидите. в результате вы сможете получить доступ ко всем методам привязки из переменной привязки.

но если у вас есть несколько тегов привязки или форм и вы хотите получить конкретную из них с помощью селектора классов, тогда машинописный скрипт предположит, что это элемент HTML, наведение покажет его, поскольку он не может просто прочитать HTML, чтобы увидеть все. но вы можете использовать его для обработки формы как HTMLForm и доступа к методам HTMLForm.

const form = document.querySelector('.new-item-form')!; //getting by class
//form is an html element
//this is a form now
//dont use the ! mark with as
const form = document.querySelector('.new-item-form') as HTMLFormElement;
//get by id
//inputs
const type = document.querySelector('#type') as HTMLSelectElement;

ООП в машинописном тексте

Свойства класса должны иметь значение по умолчанию или конструктор, иначе отображается ошибка. конструктор более стандартен.

class Invoice {
    client: string;
    details: string;
    amount: number;

    constructor(client:string, details: string, amount: number){
        this.client = client;
        this.details = details;
        this.amount = amount;
    }
}
//using invoice as type for an array
const invOne = new Invoice('mario','work on the mario website',250);
const invTwo = new Invoice('luigi','work on the mario website',300);

let invoices: Invoice[] = [];
invoices.push(invOne)
invoices.push(invTwo)
//foreach loop
invoices.forEach( invoice => {
    console.log(invoice.client, invoice.details, invoice.amount, invoice.format());
})

по умолчанию все свойства класса являются общедоступными. Чтобы предотвратить это, мы можем использовать модификаторы доступа. вы можете поставить перед ним public или нет, оно все равно будет публичным. только если вы используете другой модификатор доступа, они не являются общедоступными. чтобы сделать приватным, мы ставим приватный. Чтобы сделать его доступным только для чтения[внутри класса или вне его, никто не может его изменить], мы ставим readonly

class Invoice {
    readonly client: string; //outside class and inside class can read, cant modify
    details: string; //now its unaccessible from object, out of class
    public amount: number; //totally optional
    address: string//by default public

    ....
}

Сокращение для инициализации конструктора, а также создания свойств класса. НАМ НЕОБХОДИМО добавить модификатор доступа к свойству, чтобы использовать это сокращение.

class Invoice {
    constructor(
        readonly client: string,
        private details: string,
        public amount:number
    ){}
    //return a formatted details of an object
    format(){
        return `${this.client} owes CAD${this.amount} for ${this.details}`
    }
}

Интерфейсы в машинописном тексте:

это отличается от классов. он предназначен для предоставления структуры/подписи объекта. если вы объявляете интерфейс и переменную этого интерфейса, то эта переменная должна содержать объект (созданный с помощью {}), который имеет свойства и методы, указанные в сигнатуре интерфейса. Вы не можете добавить ничего, кроме интерфейса.

interface IsPerson {
    name: string;
    age: number;
    speak(a: string): void;
    speak(a: number): void;
}

const me:IsPerson = {}//shows eror, the object does not follow signature
const me2:IsPerson = {
    name: 'shaun',
    age: 30,
    speak(text:string):void{
        console.log(text);
    },
    spend(amount:number):number{
        return amount;
    }
} //error is gone, object follows interface signature

мы можем использовать интерфейс в качестве типа переменной для объявления переменной для обеспечения соблюдения этого типа, можем использовать его в аргументах метода для обеспечения соблюдения подписи типа.

Другое использование интерфейса, как и в Java, заключается в объявлении интерфейса и его реализации в классе, чтобы вы были уверены, что метод должен быть реализован. и так же, как мы можем объявить переменную абстрактного класса и присвоить значение дочернего класса, здесь мы можем объявить переменную интерфейса и назначить классы, реализующие этот интерфейс.

interface HasFormatter {
    format(): string;
}
Invoice implements HasFormatter{
    constructor(
        readonly client: string,
        private details: string,
        public amount:number
    ){}

//must need to implement the format method now.    
//return a formatted details of an object
    format(){
        return `${this.client} owes CAD${this.amount} for ${this.details}`
    }
}

let docOne: HasFormatter;
let docTwo: HasFormatter;

docOne = new Invoice('yoshi','web work',250);
docTwo = new Invoice('mario','plumbing work',500);

Современные браузеры уже поддерживают модуль Javascript es6. поэтому мы можем использовать модуль непосредственно в машинописном тексте. но если вы используете веб-пакет, который объединяет все в один файл, это решает все проблемы.

если вы не используете веб-пакет, вы можете увидеть это при импорте нескольких классов и модулей в файл ts (который после компиляции станет js). на вкладке сети браузера (chome) вы увидите, что все файлы js модуля загружены, что означает, что загружено слишком много файлов, что замедляет работу сайта. Для борьбы мы обычно используем веб-пакет, который объединяет все в один файл, так что если этот файл загружается, загружается все, что в целом ускоряет взаимодействие с пользователем.