Rewriting the standard classes with xparse

The problem is that hyperref redefines \@part, essentially for doing what you do yourself with the spart counter.

You don't need to use two macros, anyway. I wouldn't change the syntax of part: the optional argument should go before the mandatory one.

\documentclass{book}
\usepackage{xparse}
\usepackage{hyperref}

\makeatletter
\DeclareDocumentCommand{\part}{s O{#3} m}{%
  \cleardoublepage\thispagestyle{plain}%
  \if@twocolumn
    \onecolumn
    \@tempswatrue
  \else
   \@tempswafalse
  \fi
  \null\vfil
  \IfBooleanTF{#1}
   {% * version
    \csname phantomsection\endcsname % for hyperref
    \addcontentsline{toc}{part}{#2}%
   }
   {% standard version
    \ifnum\c@secnumdepth >-2\relax
      \refstepcounter{part}%
      \addcontentsline{toc}{part}{\thepart\hspace{1em}#2}%
    \else
      \addcontentsline{toc}{part}{#2}%
    \fi
   }%
  \markboth{}{}%
  {% print the title
   \centering \interlinepenalty\@M \normalfont
   \IfBooleanF{#1}
    {% standard version
     \ifnum \c@secnumdepth >-2\relax
       \huge\bfseries \partname~\thepart
       \par
       \vskip 20\p@
     \fi
    }%
   \Huge \bfseries #2\par
  }%
  \@endpart
}
\makeatother

\begin{document}

\tableofcontents

\part{Teil 1}
\part[Ops 2]{Teil 2}
\part*{Teil 3}
\part*[Ops 4]{Teil 4}

\end{document}

Note that you need the most recent version of xparse for this to work (release 2017/02/10 or later).

enter image description here


hyperref does a redefinition of \addcontentsline, \label and of sectioning commands, adding functionality for hyperlinks etc.

If your definition should not interfere with hyperref, it should grab the definition of \@part etc. after hyperref has done its job or redefine it after hyperref.

Wrapping the redefinition in a \AtBeginDocument{...} works.

I took the original version of the O.P. and wrapped in the \AtBeginDocument{...} hook, in my opinion, there's no need to use the latest version of xparse for this.

\documentclass{book}

\usepackage{xparse}

\newcounter{spart}% makes hyperref work

\usepackage{blindtext}
\usepackage{hyperref}

\makeatletter
\AtBeginDocument{%
\DeclareDocumentCommand{\part}{s m o}%
 {\cleardoublepage\thispagestyle{plain}%
  \if@twocolumn%
   \onecolumn%
   \@tempswatrue%
  \else%
   \@tempswafalse%
  \fi%
  \null\vfil%
 \IfNoValueTF{#3}%
  {\IfBooleanTF{#1}{\m@part*{#2}{#2}}{\m@part{#2}{#2}}}%
  {\IfBooleanTF{#1}{\m@part*{#2}{#3}}{\m@part{#2}{#3}}}}

\DeclareDocumentCommand{\m@part}{s m m}%
 {\IfBooleanTF{#1}{\refstepcounter{spart}% makes hyperref work
               \addcontentsline{toc}{part}{#3}}%
                {\ifnum \c@secnumdepth >-2\relax%
                \refstepcounter{part}%
                \addcontentsline{toc}{part}{\thepart\hspace{1em}#3}%
              \else%
                \addcontentsline{toc}{part}{#3}%
              \fi}%
    \markboth{}{}%
    {\centering%
     \interlinepenalty \@M%
    \normalfont%
  \IfBooleanF{#1}{\ifnum \c@secnumdepth >-2\relax%
              \huge\bfseries \partname~\thepart%
              \par%
              \vskip 20\p@%
              \fi}%
 \Huge \bfseries #2\par}%
\@endpart}
}
\makeatother



\begin{document}

\tableofcontents

\part{Teil 1}
\Blinddocument
\part*{Teil 2}
\Blinddocument

\end{document}