Инициализаторы текста и полей
как инициализировать новый класс TS таким образом (пример в C# чтобы показать, что я хочу):
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
устранение:
Классический JavaScript синтаксис:
return { Field1: "ASD", Field2: "QWE" };
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' } });Полезные Сценарии
- Тесты
- встроенный декларации
в моем случае я нашел это полезным в модульных тестах для двух причины:
- при тестировании ожиданий я часто хочу создать тонкий объект в качестве ожидания
- модульные тестовые платформы (например, Jasmine) могут сравнивать прототип объекта (
__proto__) и выдержали испытания. Например:var actual = new MyClass(); actual.field1 = "ASD"; expect({ field1: "ASD" }).toEqual(actual); // failsвыход сбоя модульного теста не даст подсказки о том, что не соответствует.
- в модульных тестах я могу быть избирательным о том, какие браузеры я поддержка
наконец, решение, предложенное в 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#узор.но сначала давайте рассмотрим методы, предлагаемые до сих пор, которые включают в себя:
- скопируйте конструкторы, которые принимают объект и применяют его к
Object.assign- умный
Partial<T>трюк в конструкторе копирования- использование "кастинга" против POJO
- использование
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() );
Если вы используете старую версию typescript
const typedProduct = <Product>{ code: <string>product.sku };Примечание: использование этого метода подходит только для моделей данных, так как он удалит все методы в объекте. Это в основном бросание любого объекта в a типизированный объект
Comments