[typescript] Typescript 인터페이스 기본값

TypeScript에는 다음과 같은 인터페이스가 있습니다.

interface IX {
    a: string,
    b: any,
    c: AnotherType
}

해당 유형의 변수를 선언하고 모든 속성을 초기화합니다.

let x: IX = {
    a: 'abc',
    b: null,
    c: null
}

그런 다음 나중에 init 함수에서 실제 값을 할당합니다.

x.a = 'xyz'
x.b = 123
x.c = new AnotherType()

하지만 나중에 실제 값으로 설정 될 때 객체를 선언 할 때 각 속성에 대한 기본 null 값을 지정하는 것을 좋아하지 않습니다. 인터페이스에 내가 제공하지 않는 속성을 null로 기본값으로 설정할 수 있습니까? 이 작업을 수행 할 수있는 방법 :

let x: IX = {
    a: 'abc'
}

컴파일러 오류없이. 지금 그것은 내게 말해

TS2322 : ‘{}’유형은 ‘IX’유형에 할당 할 수 없습니다. ‘{}’유형에 속성 ‘b’가 없습니다.



답변

인터페이스에 내가 제공하지 않는 속성을 null로 기본값으로 설정할 수 있습니까? 내가 이것을 할 수 있도록

아니요.하지만 기본적으로 undefined대부분 괜찮습니다. 다음 패턴을 사용할 수 있습니다. 즉, 생성 시점에 유형 어설 션이 있습니다.

let x: IX = {} as any;

x.a = 'xyz'
x.b = 123
x.c = new AnotherType()

나는 이것과 여기에 문서화 된 다른 패턴이 있습니다 :
https://basarat.gitbook.io/typescript/main-1/lazyobjectliteralinitialization


답변

인터페이스에서 기본값을 설정할 수 없지만 선택적 속성을 사용하여 원하는 작업을 수행 할 수 있습니다 (단락 # 3 비교).

https://www.typescriptlang.org/docs/handbook/interfaces.html

인터페이스를 다음과 같이 변경하기 만하면됩니다.

interface IX {
    a: string,
    b?: any,
    c?: AnotherType
}

그런 다음 다음을 수행 할 수 있습니다.

let x: IX = {
    a: 'abc'
}

그리고 할당 기본값으로 초기화 기능을 사용 x.b하고 x.c그 properies이 설정되지 않은 경우.


답변

@Timar의 대답은 null기본값 (요청 된 것)에 대해 완벽하게 작동하지만 , 여기에서 다른 기본값을 허용하는 또 다른 쉬운 솔루션 : 기본값을 포함하는 상수뿐만 아니라 옵션 인터페이스를 정의하십시오. 생성자에서 스프레드 연산자 를 사용하여 options멤버 변수 를 설정하십시오.

interface IXOptions {
    a?: string,
    b?: any,
    c?: number
}

const XDefaults: IXOptions = {
    a: "default",
    b: null,
    c: 1
}

export class ClassX {
    private options: IXOptions;

    constructor(XOptions: IXOptions) {
        this.options = { ...XDefaults, ...XOptions };
    }

    public printOptions(): void {
        console.log(this.options.a);
        console.log(this.options.b);
        console.log(this.options.c);
    }
}

이제 다음과 같은 클래스를 사용할 수 있습니다.

const x = new ClassX({ a: "set" });
x.printOptions();

산출:

set
null
1


답변

클래스로 인터페이스를 구현 한 다음 생성자에서 멤버 초기화를 처리 할 수 ​​있습니다.

class IXClass implements IX {
    a: string;
    b: any;
    c: AnotherType;

    constructor(obj: IX);
    constructor(a: string, b: any, c: AnotherType);
    constructor() {
        if (arguments.length == 1) {
            this.a = arguments[0].a;
            this.b = arguments[0].b;
            this.c = arguments[0].c;
        } else {
            this.a = arguments[0];
            this.b = arguments[1];
            this.c = arguments[2];
        }
    }
}

또 다른 접근 방식은 공장 함수를 사용하는 것입니다.

function ixFactory(a: string, b: any, c: AnotherType): IX {
    return {
        a: a,
        b: b,
        c: c
    }
}

그런 다음 간단하게 다음을 수행 할 수 있습니다.

var ix: IX = null;
...

ix = new IXClass(...);
// or
ix = ixFactory(...);


답변

Partial설명서에 설명 된대로 매핑 된 유형을 사용할 수 있습니다 .
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

귀하의 예에는 다음이 있습니다.

interface IX {
    a: string;
    b: any;
    c: AnotherType;
}

let x: Partial<IX> = {
    a: 'abc'
}


답변

나는 내가 도달 한 것보다 더 나은 방법을 찾고있는 동안 이것을 우연히 발견했다. 답변을 읽고 시험해 본 결과 다른 답변이 간결하다고 느끼지 않았기 때문에 제가하고있는 일을 게시하는 것이 가치가 있다고 생각했습니다. 새 인터페이스를 설정할 때마다 짧은 양의 코드 만 작성하면되는 것이 중요했습니다. 나는 정착했다 …

사용자 지정 일반 deepCopy 함수 사용 :

deepCopy = <T extends {}>(input: any): T => {
  return JSON.parse(JSON.stringify(input));
};

인터페이스 정의

interface IX {
    a: string;
    b: any;
    c: AnotherType;
}

… 별도의 const에 기본값을 정의하십시오.

const XDef : IX = {
    a: '',
    b: null,
    c: null,
};

그런 다음 다음과 같이 초기화하십시오.

let x : IX = deepCopy(XDef);

그게 전부입니다 ..

.. 그러나 ..

루트 요소사용자 지정 초기화 하려는 경우 사용자 지정 기본값을 허용하도록 deepCopy 함수를 수정할 수 있습니다. 함수는 다음과 같습니다.

deepCopyAssign = <T extends {}>(input: any, rootOverwrites?: any): T => {
  return JSON.parse(JSON.stringify({ ...input, ...rootOverwrites }));
};

대신 다음과 같이 호출 할 수 있습니다.

let x : IX = deepCopyAssign(XDef, { a:'customInitValue' } );

다른 선호하는 깊은 복사 방법은 작동합니다. 얕은 복사본 만 필요한 경우 Object.assign으로 충분하며 유틸리티 deepCopy또는 deepCopyAssign기능에 대한 필요성을 제거합니다 .

let x : IX = object.assign({}, XDef, { a:'customInitValue' });

알려진 문제

  • 이 모습으로 깊이 할당하지는 않지만 deepCopyAssign할당하기 전에 유형을 반복하고 확인 하도록 수정 하는 것은 그리 어렵지 않습니다 .
  • 함수와 참조는 구문 분석 / 문자열 화 프로세스에 의해 손실됩니다. 내 작업에는 필요하지 않으며 OP도 필요하지 않습니다.
  • 사용자 정의 초기화 값은 IDE에서 암시하지 않거나 실행시 유형을 확인하지 않습니다.

답변

내 솔루션 :

입력 문제를 해결하기 위해 Object.assign 위에 래퍼를 만들었습니다.

export function assign<T>(...args: T[] | Partial<T>[]): T {
  return Object.assign.apply(Object, [{}, ...args]);
}

용법:

env.base.ts

export interface EnvironmentValues {
export interface EnvironmentValues {
  isBrowser: boolean;
  apiURL: string;
}

export const enviromentBaseValues: Partial<EnvironmentValues> = {
  isBrowser: typeof window !== 'undefined',
};

export default enviromentBaseValues;

env.dev.ts

import { EnvironmentValues, enviromentBaseValues } from './env.base';
import { assign } from '../utilities';

export const enviromentDevValues: EnvironmentValues = assign<EnvironmentValues>(
  {
    apiURL: '/api',
  },
  enviromentBaseValues
);

export default enviromentDevValues;