생성 시그니처가 있는 인터페이스는 어떻게 작동하는가?
인터페이스에서 생성자를 정의하는 방식이 어떻게 작동하는지 알아내는데 어려움을 겪고 있다.내가 뭔가 완전히 오해하고 있는 것 같아.그러나 한참 동안 답을 찾아봤지만 이와 관련된 것은 찾을 수가 없다.
TypeScript 클래스에서 다음 인터페이스를 구현하는 방법:
interface MyInterface {
new ( ... ) : MyInterface;
}
안데르스 헤일스버그는 이 비디오에서 이와 유사한 것을 포함하고 있는 인터페이스를 만든다(약 14분).그러나 아무리 생각해도 나는 이것을 수업 시간에 실행할 수 없다.
내가 뭔가 오해하고 있는 것 같은데, 내가 못 알아듣는 게 뭐야?
편집:
명확히 하기 위해서."new (... )"로 나는 "무엇이든"을 의미했다.내 문제는 내가 이 일의 가장 기본적인 버전조차 얻을 수 없다는 것이다.
interface MyInterface {
new () : MyInterface;
}
class test implements MyInterface {
constructor () { }
}
이것은 나를 위한 것이 아니다. "Class 'test'가 인터페이스 'MyInterface'를 선언하지만 그것을 구현하지는 않는다.'MyInterface' 유형에는 구성 서명이 필요하지만, 컴파일하려고 할 때 'test' 유형에는 구성 서명이 없다.
편집:
그래서 이것을 좀 더 연구한 후에 피드백을 받았다.
interface MyInterface {
new () : MyInterface;
}
class test implements MyInterface {
constructor () => test { return this; }
}
유효한 TypeScript가 아니며 이것은 문제를 해결하지 못한다.생성자의 반환 형식을 정의할 수 없다.그것은 "시험"을 반환할 것이다.다음 서명: class test { constructor(){{ }}} class test는 "new()=> test"(class를 붙여넣은 코드만으로 온라인 편집기에서 "class" 위를 맴도는 것으로 관찰됨)인 것 같다.그리고 이것이 우리가 원하는 것이고 내가 생각했던 것이다.
누가 이것의 예시나 이것과 유사한 것을 제공할 수 있는가?
편집(again...):
그래서 나는 인터페이스에서는 이것을 정의할 수 있지만 TypeScript 클래스에서는 구현할 수 없는 이유에 대한 아이디어를 생각해 냈을지도 모른다.다음은 다음과 같은 작업이다.
var MyClass = (function () {
function MyClass() { }
return MyClass;
})();
interface MyInterface {
new () : MyInterface;
}
var testFunction = (foo: MyInterface) : void => { }
var bar = new MyClass();
testFunction(bar);
그렇다면 이것은 Javascript와 접속할 수 있는 TypeScript의 기능뿐인가요?아니면 Javascript를 이용하여 클래스를 구현할 필요 없이 TypeScript에서 구현이 가능한가?
인터페이스의 구성 서명은 클래스에서 구현할 수 없으며, '새로운' 기능을 정의하는 기존 JS API를 정의하기 위한 것일 뿐이다.인터페이스와 관련된 예new
작동하는 서명:
interface ComesFromString {
name: string;
}
interface StringConstructable {
new(n: string): ComesFromString;
}
class MadeFromString implements ComesFromString {
constructor (public name: string) {
console.log('ctor invoked');
}
}
function makeObj(n: StringConstructable) {
return new n('hello!');
}
console.log(makeObj(MadeFromString).name);
이렇게 하면 호출할 수 있는 항목에 대한 실제 제약 조건이 생성됨makeObj
다음 항목 포함:
class Other implements ComesFromString {
constructor (public name: string, count: number) {
}
}
makeObj(Other); // Error! Other's constructor doesn't match StringConstructable
똑같은 질문을 검색하면서 TypeScript-Team이 어떻게...
그들은 인터페이스를 선언하고 그 후에 인터페이스 이름과 정확히 일치하는 이름을 가진 변수를 선언한다.이것은 또한 정적 함수를 타이핑하는 방법이다.
예:lib.d.ts
:
interface Object {
toString(): string;
toLocaleString(): string;
// ... rest ...
}
declare var Object: {
new (value?: any): Object;
(): any;
(value: any): any;
// ... rest ...
}
나도 그렇게 해봤는데 정말 매력적으로 작용한다.
음, 구성 서명이 있는 인터페이스는 어떤 등급에서도 구현되도록 되어 있지 않다(처음에는 나처럼 C#/Java 배경을 가진 남자들에게는 이상하게 보일 수 있지만 기회를 줄 수 있다.약간 다르다.
잠시 그것을 호출서명(@기능적인 것 같이)을 가진 인터페이스라고 생각해 보라.자바 세계의 인터페이스).이것의 목적은 기능 유형을 설명하는 것이다.약간 기술된 서명은 함수 객체에 의해 충족되어야 한다...하지만 어떤 높은 수준의 기능이나 방법이 아니다.물체를 구성하는 방법을 알고 있는 함수여야 하고, 언제 부르면 불려지는 함수여야 한다.new
키워드가 사용됨.
그래서 생성 서명이 있는 인터페이스는 생성자의 서명을 정의한다!인터페이스에 정의된 서명을 준수해야 하는 클래스의 생성자(프로젝터가 인터페이스를 구현한다고 생각함)그것은 공장같다!
다음은 가장 일반적인 사용법을 설명하려는 짧은 코드 조각이다.
interface ClassicInterface { // old school interface like in C#/Java
method1();
...
methodN();
}
interface Factory { //knows how to construct an object
// NOTE: pay attention to the return type
new (myNumberParam: number, myStringParam: string): ClassicInterface
}
class MyImplementation implements ClassicInterface {
// The constructor looks like the signature described in Factory
constructor(num: number, s: string) { } // obviously returns an instance of ClassicInterface
method1() {}
...
methodN() {}
}
class MyOtherImplementation implements ClassicInterface {
// The constructor looks like the signature described in Factory
constructor(n: number, s: string) { } // obviously returns an instance of ClassicInterface
method1() {}
...
methodN() {}
}
// And here is the polymorphism of construction
function instantiateClassicInterface(ctor: Factory, myNumberParam: number, myStringParam: string): ClassicInterface {
return new ctor(myNumberParam, myStringParam);
}
// And this is how we do it
let iWantTheFirstImpl = instantiateClassicInterface(MyImplementation, 3.14, "smile");
let iWantTheSecondImpl = instantiateClassicInterface(MyOtherImplementation, 42, "vafli");
공식 문서로부터
클래스가 인터페이스를 구현할 때 클래스의 인스턴스 쪽만 확인되기 때문이다.시공자가 정적 측에 앉기 때문에 이 점검에는 포함되지 않는다.
대신에, 당신은 수업의 정적 측면을 직접적으로 다룰 필요가 있을 것이다.이 예에서는 두 가지 인터페이스, 즉 생성자를 위한 ClockConstructor와 인스턴스(instance) 방법을 위한 ClockInterface를 정의한다.그런 다음 편의를 위해 전달된 유형의 인스턴스를 생성하는 생성자 createClock을 정의한다.
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick(): void;
}
function createClock(
ctor: ClockConstructor,
hour: number,
minute: number
): ClockInterface {
return new ctor(hour, minute);
}
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log("beep beep");
}
}
class AnalogClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log("tick tock");
}
}
let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);
설계 관점에서 인터페이스에서 생성자 요구사항을 지정하는 것은 보통이 아니다.인터페이스는 개체에 대해 수행할 수 있는 작업을 설명해야 한다.인터페이스를 구현하는 다른 클래스는 필요한 경우 다른 생성자 매개변수를 요구하도록 허용해야 한다.
예를 들어 인터페이스가 있는 경우:
interface ISimplePersistence {
load(id: number) : string;
save(id: number, data: string): void;
}
나는 데이터를 쿠키로 저장하기 위한 구현이 있을 수 있는데, 이것은 생성자 매개변수가 필요 없고, 연결 문자열이 생성자 매개변수로 필요하다.
여전히 인터페이스에서 생성자를 정의하려면 더러운 방법으로 이 작업을 수행할 수 있으며, 나는 이 질문에 답하곤 했다.
의도된 행동을 달성하기 위해 당신은 장식가들을 사용할 수 있다. 비록 그것이 그들이 사용되어야 하는 것이 아닐지라도.
이것
interface MyInterface {
new ();
}
function MyInterfaceDecorator(constructor: MyInterface) {
}
@MyInterfaceDecorator
class TestClass {
constructor () { }
}
문제없이 편찬하다이와 대조적으로 TestClass에 대한 다음 정의는
// error TS2345: Argument of type 'typeof TestClass' is not assignable to parameter of type 'MyInterface'.
@MyInterfaceDecorator
class TestClass {
constructor (arg: string) { }
}
편집하지 않을 것이다.
닐스의 대답을 확대하기 위해, 당신은 또한 일반적인 것을 만들 수 있다.new
기법으로 할 수 있는것-동일기구의 기법:
interface MyArrayConstructor {
<T>(...elements: Array<T>): MyArrayInstance<T>
new <T> (...elements: Array<T>): MyArrayInstance<T>
}
// “Typecast” not the function itself, but another symbol,
// so that the body of myArray will also benefit from
// type-checking:
export const MyArray = myArray as MyArrayConstructor
interface MyArrayInstance<T> {
push(...args: Array<T>): number
slice(from?: number, to?:number): Array<T>
}
function myArray(...elements: Array<T>): MyArrayInstance<T> {
return {
push(...args) { ... },
slice(from?: number, to?: number) { ... }
}
}
참조URL: https://stackoverflow.com/questions/13407036/how-does-interfaces-with-construct-signatures-work
'programing' 카테고리의 다른 글
페이지 새로 고침 없이 Vuex 상태가 업데이트되지 않음 (0) | 2022.03.07 |
---|---|
정적 함수를 Ract ES6 클래스로 호출 (0) | 2022.03.07 |
형식 지정 열거형 값을 배열로 표시 (0) | 2022.03.07 |
서로 다른 시작점과 끝점으로 어레이 반복 (0) | 2022.03.07 |
vue-roouter를 사용하여 소품에 쿼리 바인딩 (0) | 2022.03.07 |