getStyles<T extends keyof CSSStyleDeclaration>(styles: readonly T[]) {
return styles.reduce((res, style) => {
res[style] = this.$nativeElement.style[style];
return res;
}, {} as Pick<CSSStyleDeclaration, T>);
}
CSSStyleDeclaration
. const foo = {
bar: 1
};
foo['bar'] // 1
const baz = {
qux: 2
}['qux']; // 2
тайпскрит в работе с типами тут ничем не отличается: type user = {
id: number,
name: string,
};
type id = user['id']; // number
type userKeys = keyof user; // 'id' | 'name'
type userTypes = user[keyof user]; // number | string
тип never
же просто не учитывается: number | string | never
- то же самое что number | string
. foo as unknown as Type
- двойным кастованием вы можете скастовать что угодно во что угодно. T extends [], K extends keyof T
- K
тут что-то производное от number
, потому что ключи(keyof) массива([]) - только цифры.let resultSort: T = arr;
- бессмысленно, так как arr.sort
в любом случае меняет исходный массив.a[propertyName].toLowerCase()
- упадёт если propertyName
будет year
, т.к. Number не имеет метода toLowerCase
.function sortArray<T extends {[key: string]: unknown}, K extends keyof T> (originArr: T[], propertyName: K, cb: (a: T[]) => T[]): T[] {
let arr: T[] = JSON.parse(JSON.stringify(originArr)); //deep copy array
arr.sort((a, b) => {
let nameA = String(a[propertyName]).toLowerCase(),
nameB = String(b[propertyName]).toLowerCase();
if (nameA < nameB)
return -1;
if (nameA > nameB)
return 1;
return 0;
});
return cb(arr);
}
String
, но тогда вместо unknown
надо указать конкретные типы с которыми предполагается работать, и в самой функции сортировки их учесть. tsc -d --outDir ./dist
и package.json, смотрящий на результат. state.books.filter((book: { id: string }) => book.id !== id)
А лучше: interface Book {
id: string;
// ...
}
state.books.filter((book: Book) => book.id !== id)
А ещё лучше: interface Book {
id: string;
// ...
}
interface State {
books: Book[];
// ...
}
const state: State = ...
state.books.filter(book => book.id !== id)
class Main {
constructor(public name: string) {}
}
class Sub extends Main {
constructor(name: string, public lastname: string) {
super(name)
}
}
const sub = new Sub('michael', 'jackson')
function hello (person: Main) {
console.log(person.name)
if(person instanceof Sub) {
console.log(person.lastname)
}
}
hello(sub)
interface Dictionary<T> {
[key: string]: T
}
function serialize<T extends Dictionary<string | number[]>> (arg: T) {
var res = '';
var replaceNamePop: Dictionary<string> = {
modules: 'module',
categories: 'category',
searchFieldsList: 'searchFieldList'
};
Object.keys(arg).forEach(function (this: T, key) {
if (Array.isArray(this[key])) {
for (var j = 0; j < this[key].length; j++) {
if (typeof replaceNamePop[key] != 'undefined')
res += '&' + replaceNamePop[key] + '=' + this[key][j];
else
res += '&' + key + '=' + this[key][j];
}
} else {
if (typeof replaceNamePop[key] != 'undefined')
res += '&' + replaceNamePop[key] + '=' + this[key];
else
res += '&' + key + '=' + this[key];
}
}, arg);
return res;
}
serialize({
'modules': [20],
'categories': [20],
'keyword': 'keyword',
'time': 'time',
'catRelation': 'cat',
'sortField': 'sort',
'sortDirection': 'ASC',
'searchFieldsList': 'list'
});
serialize({
'modules': [20, 25],
'categories': [20, 58],
'keyword': 'keyword',
'time': 'time',
'catRelation': 'cat',
'sortField': 'sort',
'sortDirection': 'ASC',
'searchFieldsList': 'list'
});
serialize({
'modules': [20, 25],
'keyword': 'keyword'
});
declare module '*.scss' {
const scss: any;
export default scss
}
, чтоб он знал какие там где типы.class FormBuilder {
public static strategies: { [key: string]: {new(): IFormStrategy} } = {
simple: SimpleFormStrategy,
extended: ExtendedFormStrategy,
};
public build(params: { strategy: string }): Form {
let strategy: IFormStrategy = new FormBuilder.strategies[params.strategy]();
return strategy.execute(params);
}
}
FormBuilder.strategies.custom = CustomFormStrategy;
const formBuilder = new FormBuilder();
formBuilder.build({ strategy: 'custosm' });