2017-09-10 32 views
1

Adobe의 ExtendScript는 화면상의 거리를 나타내는 UnitValue 유형을 제공합니다. 이것은 Number 유형과 유사하지만 구별되는 유형입니다.TypeScript에서 Adobe의 숫자와 유사한 'UnitValue'표현

  1. UnitValue 목적은 예 "cm" 또는 "ft" 들면 type 문자열을 행한다.
  2. 다른 type 값을 갖는 UnitValue 사이의 산술 연산에는 암시 적 강제 변환이 필요합니다. UnitValue 개체와 일반 Number 사이의 산술 연산은있는 그대로 발생하여 UnitValue을 반환합니다.
  3. UnitValue 개체는 여러 필드를 포함합니다. UnitValue 프로토 타입은 많은 방법을 구현합니다.
  4. UnitValue 개체는 생성자 - var x = UnitValue(4, "cm")에서 생성됩니다.

어떻게 이것을 TypeScript에서 가장 잘 표현할 수 있습니까?

+0

새 UnitValue는 어떻게 만듭니 까? 생성자가 있습니까? 아니면 전화해야하는 기능입니까? –

+0

'+'연산자를 사용하여 함께 추가 할 수 있습니까? 그렇게 불행하게도 내가 알고있는 한 Typescript에서 모델링 할 수 없다. –

답변

0

구현 방법 중 하나는 기본 단위로 센티미터를 선택했지만 다른 것을 사용할 수 있습니다. 위에서 설명한 것처럼 인스턴스 메소드를 사용하여 TypeScript에서 연산자를 오버로드 할 수 없습니다. 나는 인수가 아니라 메소드가 호출 된 인스턴스의 유형 (단위)을 유지하기로했다.

설명을 보려면 코드의 주석을 확인하고 질문이 있는지 물어보십시오. 이런 식으로 사용

export interface IUnitValue { 
    add(a: IUnitValue): IUnitValue; 
    subtract(a: IUnitValue): IUnitValue; 
    toString(): string; 
} 

export type Unit = "cm" | "ft"; 

// UnitValue is a factory function that knows how to construct different 
// types of UnitValueClass 
export const UnitValue = (value: number, unit: Unit): IUnitValue => { 
    switch (unit) { 
     case "cm": 
      return new UnitValueClass(value, 1, unit); 
     case "ft": 
      return new UnitValueClass(value, 30, unit); 
    } 
    throw new Error(`Unrecognised unit ${unit}`); 
}; 

export class UnitValueClass implements IUnitValue { 
    private value: number; 
    private cmPerUnit: number; 
    private type: Unit; 

    constructor(value: number, cmPerUnit: number, unit: Unit) { 
     this.value = value; 
     this.cmPerUnit = cmPerUnit; 
     this.type = unit; 
    } 

    // Return the wrapped value converted to centimeters 
    private toCm(): number { 
     return this.value * this.cmPerUnit; 
    } 

    // When adding, convert both operands to centimeters, then convert the result 
    // to the correct type and return a new UnitValue 
    add(a: this): IUnitValue { 
     return UnitValue((this.toCm() + a.toCm())/this.cmPerUnit, this.type); 
    } 

    // Same logic as adding 
    subtract(a: this): IUnitValue { 
     return UnitValue((this.toCm() - a.toCm())/this.cmPerUnit, this.type); 
    } 

    // Make it look pretty 
    toString() { 
     return `${this.value} ${this.type}`; 
    } 
} 

: 타이프에서 일반적이고 문자 유형을 사용하여

const a = UnitValue(45, "cm"); 
const b = UnitValue(1, "ft"); 

console.log(a.toString());   // 45 cm 
console.log(b.toString());   // 1 ft 
console.log(b.add(a).toString());  // 2.5 ft 
console.log(a.subtract(b).toString());// 15 cm 
0

그것은 기술적으로 구현하기 위해 단위 : 이런

// union of all possible unit types 
type UnitType = 'cm' | 'm'; 

interface UnitConversion<From extends UnitType, To extends UnitType> { 
    from: From; 
    to: To; 
    convert(value: UnitValue<From>): UnitValue<To>; 
} 

function conversion<From extends UnitType, To extends UnitType>(
    from: From, to: To, convert: (value: UnitValue<From>) => UnitValue<To> 
): UnitConversion<From, To> { 
    return { from, to, convert }; 
} 

function identity<T extends UnitType>(t: T): UnitConversion<T, T> { 
    return { from: t, to: t, convert: v => v }; 
} 

// conversion table for each pair of unit types 
const IMPLICIT_CONVERSIONS = { 
    'cm': { 
     'cm': identity('cm'), 
     'm': conversion('cm', 'm', v => new UnitValue(v.value * 0.1, 'm')), 
    }, 
    'm': { 
     'cm': conversion('m', 'm', v => new UnitValue(v.value * 10, 'cm')), 
     'm': identity('m'), 
    }, 
}; 
type ImplicitConversions< 
    Left extends UnitType, 
    Right extends UnitType 
> = (typeof IMPLICIT_CONVERSIONS)[Left][Right]['to']; 

function convert(conversion: UnitConversion<any, any>, value: UnitValue<any>) { 
    return value.type === conversion.to ? value : conversion.convert(value); 
} 

type UnitPair<T extends UnitType> = { 
    left: UnitValue<T>; 
    right: UnitValue<T>; 
}; 

function convertToCommonType<Left extends UnitType, Right extends UnitType>(
    left: UnitValue<Left>, 
    right: UnitValue<Right> 
): UnitPair<ImplicitConversions<Left, Right>> { 
    const conversion = IMPLICIT_CONVERSIONS[left.type][right.type]; 
    return { left: convert(conversion, left), right: convert(conversion, right) }; 
} 

class UnitValue<Type extends UnitType> { 
    constructor(
     readonly value: number, 
     readonly type: Type, 
    ) { } 

    /** Type-safe unit addition */ 
    add<T extends UnitType>(value: UnitValue<T>): UnitValue<ImplicitConversions<Type, T>> { 
     const { left, right } = convertToCommonType(this, value); 
     return new UnitValue(left.value + right.value, left.type); 
    } 
} 
다음

사용 :

const common = convertToCommonType(
    new UnitValue(3, 'cm'), 
    new UnitValue(10, 'm') 
); 
// => result type: UnitValue<'m'> 

const z = new UnitValue(4, 'cm').add(new UnitValue(5, 'm')); 
// => result type: UnitValue<'m'> 

그러나, 이것이 너무 많은 복잡성을 야기한다고 주장한다.