Typescript передает поля через конструктор с проверкой типа

#javascript #typescript

#javascript #typescript

Вопрос:

Я пытаюсь передать объект fields через объект конструктора :

 new Alloy({ name: "foo" })
  

Проблема в том, что тип не проверяется :

 export class Alloy {

    name!: string

    constructor(data: Partial<Alloy>) {
        Object.assign<Alloy, Alloy>(this, {
            name: data.name!
        });
    }
}
  

Например, см. Мой второй тест ( is mandatory ) не выдает ошибку, и ожидается, что :

 import { Alloy } from "./Alloy"

describe("Alloy", () => {

    const defaultParams = {
        name: "Foo bar"
    }

    describe("has a name", () => {
        test("is a string", async () => {
            const alloy = new Alloy({ ...defaultParams, name: "Foo bar" })

            expect(alloy.name).toEqual("Foo bar")
            expect(typeof alloy.name === "string").toBeTruthy()
        })

        // this test is failing
        test("is mandatory", async () => {
            const t = () => {
                const alloy = new Alloy({ ...defaultParams, name: undefined })
            };
            expect(t).toThrow(TypeError);
        })
    });
})
  

Комментарии:

1. Какую ошибку вы получаете?

2. поскольку я передаю неопределенное имя, я ожидаю получить ошибку. Затем второй тест не удался, потому что он ничего не выдает ( Received function did not throw )

3. Имя не требуется в вашей модели Alloy . Вам нужно установить тип строки имени и не делать его необязательным 🙂

4. Как это сделать? name!: string the ! маркер задает имя, как требуется? нет ?

5. имя @Xero! пропускает проверку null / undefined для этого свойства, что принудительно обходит требуемое поведение

Ответ №1:

Проблема заключается в определении вашего класса. Добавляя ! s, вы сообщаете TS, что знаете, что оно не будет undefined / null — не то, чтобы это было обязательно.

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

Если вы объявите класс таким образом, вы позволите TS показать вам проблемы:

 export class Alloy {

    name: string

    constructor(data: Partial<Alloy>) {
        Object.assign<Alloy, Alloy>(this, {
            name: data.name,
        });
    }
}
  

Теперь вы получаете ошибки, сообщающие вам, что имя не гарантировано как неопределенное, и что data.name также может быть неопределенным, поэтому не может быть присвоено требуемому свойству.

Комментарии:

1. Спасибо за ваш ответ, но это не работает, я получаю Property 'name' has no initializer and is not definitely assigned in the constructor.ts(2564)

2. @Xero — да — но я думал, что ваш вопрос был «почему это не сбой»? Теперь это не удается, потому что это неверно. Как вы собираетесь это работать? Если вы хотите, чтобы были определены все свойства, вы не должны инициализировать его с помощью Partial . Если вы можете предоставить дополнительную информацию об ожидаемом поведении, я могу попытаться найти решение

3. Вы можете либо: A. проверить, задано ли имя, и выдать ошибку времени выполнения, если это не так. B. потребовать, чтобы имя было задано в аргументах вашего конструктора, заменив Partial<Alloy> на Partial<Alloy> amp; {name: string} .