Инициализаторы текста и полей



как инициализировать новый класс TS таким образом (пример в C# чтобы показать, что я хочу):



// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after


устранение:

Классический JavaScript синтаксис:



return { Field1: "ASD", Field2: "QWE" };
530   10  

10 ответов:

существует проблема на TypeScript codeplex, который описывает это:поддержка инициализаторов объектов.

Как уже говорилось, Вы можете сделать это с помощью интерфейсов в TypeScript вместо классов:

interface Name {
    first: string;
    last: string;
}
class Person {
    name: Name;
    age: number;
}

var bob: Person = {
    name: {
        first: "Bob",
        last: "Smith",
    },
    age: 35,
};

Обновлено 07/12/2016: Typescript 2.1 вводит сопоставленные типы обеспечивает Partial<T>, которая позволяет вам сделать это....

class Person {
    public name: string = "default"
    public address: string = "default"
    public age: number = 0;

    public constructor(init?:Partial<Person>) {
        Object.assign(this, init);
    }
}

let persons = [
    new Person(),
    new Person({}),
    new Person({name:"John"}),
    new Person({address:"Earth"}),    
    new Person({age:20, address:"Earth", name:"John"}),
];

Оригинальный Ответ:

мой подход заключается в определении отдельной fields переменная, которую вы передаете конструктору. Хитрость заключается в том, чтобы переопределить все поля класса для этого инициализатора как необязательные. Когда объект создается (с его значениями по умолчанию), вы просто назначаете объект инициализатора на this;

export class Person {
    public name: string = "default"
    public address: string = "default"
    public age: number = 0;

    public constructor(
        fields?: {
            name?: string,
            address?: string,
            age?: number
        }) {
        if (fields) Object.assign(this, fields);
    }
}

или сделать это вручную (более безопасный):

if (fields) {
    this.name = fields.name || this.name;       
    this.address = fields.address || this.address;        
    this.age = fields.age || this.age;        
}

использование:

let persons = [
    new Person(),
    new Person({name:"Joe"}),
    new Person({
        name:"Joe",
        address:"planet Earth"
    }),
    new Person({
        age:5,               
        address:"planet Earth",
        name:"Joe"
    }),
    new Person(new Person({name:"Joe"})) //shallow clone
]; 

и вывод на консоль:

Person { name: 'default', address: 'default', age: 0 }
Person { name: 'Joe', address: 'default', age: 0 }
Person { name: 'Joe', address: 'planet Earth', age: 0 }
Person { name: 'Joe', address: 'planet Earth', age: 5 }
Person { name: 'Joe', address: 'default', age: 0 }   

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

вы также можете смешать его с необходимыми параметрами конструктора тоже -- stick fields на конце.

О как близко к стилю C#, как вы собираетесь получить я думаю (фактическое поле-init синтаксис был отклонен). Я бы предпочел правильный инициализатор поля, но пока не похоже, что это произойдет.

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

вы можете повлиять на анонимный объект, приведенный в вашем типе класса. бонус: в visual studio вы пользуетесь intellisense таким образом:)

var anInstance: AClass = <AClass> {
    Property1: "Value",
    Property2: "Value",
    PropertyBoolean: true,
    PropertyNumber: 1
};

Edit:

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

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

interface IClass {
   Property1: string;
   Property2: string;
   PropertyBoolean: boolean;
   PropertyNumber: number;
}

var anObject: IClass = <IClass> {
     Property1: "Value",
     Property2: "Value",
     PropertyBoolean: true,
     PropertyNumber: 1
 };

в некоторых сценариях может быть приемлемо использовать Object.create. Ссылка Mozilla включает в себя полифилл, если вам нужна обратная совместимость или вы хотите свернуть свою собственную функцию инициализатора.

применительно к вашему примеру:

Object.create(Person.prototype, {
    'Field1': { value: 'ASD' },
    'Field2': { value: 'QWE' }
});

Полезные Сценарии

  • Тесты
  • встроенный декларации

в моем случае я нашел это полезным в модульных тестах для двух причины:

  1. при тестировании ожиданий я часто хочу создать тонкий объект в качестве ожидания
  2. модульные тестовые платформы (например, Jasmine) могут сравнивать прототип объекта (__proto__) и выдержали испытания. Например:
var actual = new MyClass();
actual.field1 = "ASD";
expect({ field1: "ASD" }).toEqual(actual); // fails

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

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

наконец, решение, предложенное в http://typescript.codeplex.com/workitem/334 не поддерживает встроенное объявление в стиле json. Например, не компилируется следующее:

var o = { 
  m: MyClass: { Field1:"ASD" }
};

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

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

class MyClass{
    constructor(public Field1:string = "", public Field2:string = "")
    {
        // other constructor stuff
    }
}

var myClass = new MyClass("ASD", "QWE");
alert(myClass.Field1); // voila! statement completion on these properties

Я предлагаю подход, который не требует Typescript 2.1:

class Person {
    public name: string;
    public address?: string;
    public age: number;

    public constructor(init:Person) {
        Object.assign(this, init);
    }

    public someFunc() {
        // todo
    }
}

let person = new Person(<Person>{ age:20, name:"John" });
person.someFunc();

ключевые моменты:

  • Typescript 2.1 не требуется,Partial<T> не требуется
  • он поддерживает функции (по сравнению с простым утверждением типа, которое не поддерживает функции)

Ниже приводится решение, которое сочетает в себе более короткое применение Object.assign чтобы более точно моделировать оригинал C# узор.

но сначала давайте рассмотрим методы, предлагаемые до сих пор, которые включают в себя:

  1. скопируйте конструкторы, которые принимают объект и применяют его к Object.assign
  2. умный Partial<T> трюк в конструкторе копирования
  3. использование "кастинга" против POJO
  4. использование Object.create вместо Object.assign

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

Короткий, Универсальный Ответ!--30-->

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

const john = Object.assign( new Person(), {
    name: "John",
    age: 29,
    address: "Earth"
});

вот и все. Единственное дополнение над C# шаблон Object.assign вместе с 2 скобками и запятой. Проверьте рабочий пример ниже, чтобы подтвердить, что он поддерживает прототипы функций типа. Никаких конструкторов не требуется, и никаких умных трюков.

Пример Работающего

в этом примере показано, как инициализировать объект, используя приближение a C# поле инициализатор:

class Person {
    name: string = '';
    address: string = '';
    age: number = 0;

    aboutMe() {
        return `Hi, I'm ${this.name}, aged ${this.age} and from ${this.address}`;
    }
}

// typescript field initializer (maintains "type" definition)
const john = Object.assign( new Person(), {
    name: "John",
    age: 29,
    address: "Earth"
});

// initialized object maintains aboutMe() function prototype
console.log( john.aboutMe() );

самый простой способ сделать это с Тип литья.

return <MyClass>{ Field1: "ASD", Field2: "QWE" };

Если вы используете старую версию typescript

const typedProduct = <Product>{
                    code: <string>product.sku
                };

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

может также привести с помощью:

   return { 
     Field1: "ASD", 
     Field2: "QWE" 
   } as MyClass;

Comments

    Ничего не найдено.